aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml6
-rw-r--r--.gitmodules4
-rw-r--r--CMakeLists.txt30
-rw-r--r--CMakeLists_IOS.txt2
-rw-r--r--LICENSE2
-rw-r--r--Makefile2
-rw-r--r--README.md18
-rw-r--r--ZMQ.md61
-rw-r--r--cmake/32-bit-toolchain.cmake2
-rw-r--r--cmake/64-bit-toolchain.cmake2
-rw-r--r--cmake/FindCcache.cmake15
-rw-r--r--cmake/FindUnbound.cmake2
-rw-r--r--cmake/GitVersion.cmake2
-rw-r--r--cmake/Version.cmake2
-rw-r--r--cmake/test-libusb-version.c2
-rw-r--r--cmake/test-protobuf.cpp2
-rw-r--r--cmake/test-static-assert.c2
-rw-r--r--cmake/test-static-assert.cpp2
-rw-r--r--contrib/CMakeLists.txt2
-rw-r--r--contrib/codefresh/codefresh.yml18
-rw-r--r--contrib/depends/toolchain.cmake.in5
-rw-r--r--contrib/epee/CMakeLists.txt2
-rw-r--r--contrib/epee/include/byte_slice.h26
-rw-r--r--contrib/epee/include/byte_stream.h224
-rw-r--r--contrib/epee/include/console_handler.h4
-rw-r--r--contrib/epee/include/int-util.h2
-rw-r--r--contrib/epee/include/md5_l.inl12
-rw-r--r--contrib/epee/include/memwipe.h2
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h3
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl19
-rw-r--r--contrib/epee/include/net/connection_basic.hpp2
-rw-r--r--contrib/epee/include/net/http_auth.h2
-rw-r--r--contrib/epee/include/net/http_server_impl_base.h2
-rw-r--r--contrib/epee/include/net/net_fwd.h2
-rw-r--r--contrib/epee/include/net/network_throttle-detail.hpp2
-rw-r--r--contrib/epee/include/net/network_throttle.hpp6
-rw-r--r--contrib/epee/include/rolling_median.h2
-rw-r--r--contrib/epee/include/span.h2
-rw-r--r--contrib/epee/include/storages/levin_abstract_invoke2.h9
-rw-r--r--contrib/epee/include/storages/parserse_base_utils.h2
-rw-r--r--contrib/epee/include/storages/portable_storage_bin_utils.h2
-rw-r--r--contrib/epee/include/wipeable_string.h2
-rw-r--r--contrib/epee/src/CMakeLists.txt7
-rw-r--r--contrib/epee/src/byte_slice.cpp67
-rw-r--r--contrib/epee/src/byte_stream.cpp93
-rw-r--r--contrib/epee/src/connection_basic.cpp2
-rw-r--r--contrib/epee/src/http_auth.cpp2
-rw-r--r--contrib/epee/src/int-util.cpp2
-rw-r--r--contrib/epee/src/levin_base.cpp2
-rw-r--r--contrib/epee/src/memwipe.c2
-rw-r--r--contrib/epee/src/mlog.cpp2
-rw-r--r--contrib/epee/src/net_ssl.cpp2
-rw-r--r--contrib/epee/src/network_throttle-detail.cpp2
-rw-r--r--contrib/epee/src/network_throttle.cpp2
-rw-r--r--contrib/epee/src/wipeable_string.cpp2
-rw-r--r--contrib/gitian/README.md4
-rw-r--r--contrib/gitian/gitian-android.yml2
-rw-r--r--contrib/gitian/gitian-freebsd.yml2
-rw-r--r--contrib/gitian/gitian-linux.yml2
-rw-r--r--contrib/gitian/gitian-osx.yml2
-rw-r--r--contrib/gitian/gitian-win.yml2
-rwxr-xr-xcontrib/snap/monerod-wrapper8
-rw-r--r--contrib/snap/monerod.conf10
-rw-r--r--contrib/snap/setup/gui/icon.pngbin1531 -> 0 bytes
-rw-r--r--contrib/snap/snapcraft.yaml78
-rw-r--r--external/CMakeLists.txt1
-rw-r--r--external/easylogging++/easylogging++.cc96
-rw-r--r--external/qrcodegen/CMakeLists.txt7
-rw-r--r--external/qrcodegen/QrCode.cpp862
-rw-r--r--external/qrcodegen/QrCode.hpp556
m---------external/supercop0
-rw-r--r--include/INode.h2
-rw-r--r--include/IWallet.h2
l---------snap1
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/blockchain_db/CMakeLists.txt2
-rw-r--r--src/blockchain_db/blockchain_db.cpp45
-rw-r--r--src/blockchain_db/blockchain_db.h17
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp71
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h5
-rw-r--r--src/blockchain_db/locked_txn.h2
-rw-r--r--src/blockchain_db/testdb.h7
-rw-r--r--src/blockchain_utilities/CMakeLists.txt2
-rw-r--r--src/blockchain_utilities/README.md2
-rw-r--r--src/blockchain_utilities/blockchain_ancestry.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_blackball.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_depth.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_export.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_prune_known_spent_data.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_stats.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_usage.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_utilities.h2
-rw-r--r--src/blockchain_utilities/blocksdat_file.cpp2
-rw-r--r--src/blockchain_utilities/blocksdat_file.h3
-rw-r--r--src/blockchain_utilities/bootstrap_file.cpp2
-rw-r--r--src/blockchain_utilities/bootstrap_file.h3
-rw-r--r--src/blockchain_utilities/bootstrap_serialization.h2
-rw-r--r--src/blocks/CMakeLists.txt2
-rw-r--r--src/blocks/checkpoints.datbin244676 -> 261572 bytes
-rw-r--r--src/checkpoints/CMakeLists.txt2
-rw-r--r--src/checkpoints/checkpoints.cpp127
-rw-r--r--src/checkpoints/checkpoints.h15
-rw-r--r--src/common/CMakeLists.txt5
-rw-r--r--src/common/aligned.c2
-rw-r--r--src/common/apply_permutation.h2
-rw-r--r--src/common/base58.cpp2
-rw-r--r--src/common/base58.h2
-rw-r--r--src/common/boost_serialization_helper.h2
-rw-r--r--src/common/command_line.cpp2
-rw-r--r--src/common/command_line.h2
-rw-r--r--src/common/common_fwd.h2
-rw-r--r--src/common/dns_utils.cpp2
-rw-r--r--src/common/dns_utils.h2
-rw-r--r--src/common/download.cpp2
-rw-r--r--src/common/download.h2
-rw-r--r--src/common/http_connection.h2
-rw-r--r--src/common/i18n.cpp2
-rw-r--r--src/common/i18n.h2
-rw-r--r--src/common/json_util.h2
-rw-r--r--src/common/notify.cpp2
-rw-r--r--src/common/notify.h7
-rw-r--r--src/common/password.cpp2
-rw-r--r--src/common/password.h2
-rw-r--r--src/common/perf_timer.cpp2
-rw-r--r--src/common/perf_timer.h2
-rw-r--r--src/common/pod-class.h2
-rw-r--r--src/common/rpc_client.h2
-rw-r--r--src/common/scoped_message_writer.h2
-rw-r--r--src/common/sfinae_helpers.h2
-rw-r--r--src/common/stack_trace.cpp2
-rw-r--r--src/common/stack_trace.h2
-rw-r--r--src/common/threadpool.cpp2
-rw-r--r--src/common/threadpool.h2
-rw-r--r--src/common/unordered_containers_boost_serialization.h2
-rw-r--r--src/common/updates.cpp2
-rw-r--r--src/common/updates.h2
-rw-r--r--src/common/utf8.h114
-rw-r--r--src/common/util.cpp2
-rw-r--r--src/common/util.h2
-rw-r--r--src/common/varint.h2
-rw-r--r--src/crypto/CMakeLists.txt5
-rw-r--r--src/crypto/blake256.c2
-rw-r--r--src/crypto/blake256.h2
-rw-r--r--src/crypto/c_threads.h2
-rw-r--r--src/crypto/chacha.h2
-rw-r--r--src/crypto/crypto-ops-data.c2
-rw-r--r--src/crypto/crypto-ops.c2
-rw-r--r--src/crypto/crypto-ops.h2
-rw-r--r--src/crypto/crypto.cpp141
-rw-r--r--src/crypto/crypto.h15
-rw-r--r--src/crypto/crypto_ops_builder/README.md2
-rw-r--r--src/crypto/crypto_ops_builder/crypto-ops-data.c2
-rw-r--r--src/crypto/crypto_ops_builder/crypto-ops-old.c2
-rw-r--r--src/crypto/crypto_ops_builder/crypto-ops.h2
-rw-r--r--src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py2
-rw-r--r--src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h2
-rw-r--r--src/crypto/generic-ops.h2
-rw-r--r--src/crypto/groestl.h2
-rw-r--r--src/crypto/groestl_tables.h2
-rw-r--r--src/crypto/hash-extra-blake.c2
-rw-r--r--src/crypto/hash-extra-groestl.c2
-rw-r--r--src/crypto/hash-extra-jh.c2
-rw-r--r--src/crypto/hash-extra-skein.c2
-rw-r--r--src/crypto/hash-ops.h2
-rw-r--r--src/crypto/hash.c2
-rw-r--r--src/crypto/hash.h2
-rw-r--r--src/crypto/initializer.h2
-rw-r--r--src/crypto/keccak.c12
-rw-r--r--src/crypto/random.c2
-rw-r--r--src/crypto/random.h2
-rw-r--r--src/crypto/rx-slow-hash.c2
-rw-r--r--src/crypto/skein_port.h2
-rw-r--r--src/crypto/slow-hash.c2
-rw-r--r--src/crypto/tree-hash.c2
-rw-r--r--src/crypto/wallet/CMakeLists.txt62
-rw-r--r--src/crypto/wallet/crypto.h56
-rw-r--r--src/crypto/wallet/empty.h.in31
-rw-r--r--src/cryptonote_basic/CMakeLists.txt2
-rw-r--r--src/cryptonote_basic/account.cpp104
-rw-r--r--src/cryptonote_basic/account.h21
-rw-r--r--src/cryptonote_basic/account_boost_serialization.h2
-rw-r--r--src/cryptonote_basic/blobdatatype.h2
-rw-r--r--src/cryptonote_basic/connection_context.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp2
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h2
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h2
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp4
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h2
-rw-r--r--src/cryptonote_basic/difficulty.cpp2
-rw-r--r--src/cryptonote_basic/difficulty.h2
-rw-r--r--src/cryptonote_basic/events.h46
-rw-r--r--src/cryptonote_basic/fwd.h36
-rw-r--r--src/cryptonote_basic/hardfork.cpp2
-rw-r--r--src/cryptonote_basic/hardfork.h2
-rw-r--r--src/cryptonote_basic/miner.cpp2
-rw-r--r--src/cryptonote_basic/miner.h2
-rw-r--r--src/cryptonote_basic/subaddress_index.h2
-rw-r--r--src/cryptonote_basic/tx_extra.h2
-rw-r--r--src/cryptonote_basic/verification_context.h2
-rw-r--r--src/cryptonote_config.h8
-rw-r--r--src/cryptonote_core/CMakeLists.txt2
-rw-r--r--src/cryptonote_core/blockchain.cpp246
-rw-r--r--src/cryptonote_core/blockchain.h28
-rw-r--r--src/cryptonote_core/blockchain_storage_boost_serialization.h2
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp90
-rw-r--r--src/cryptonote_core/cryptonote_core.h39
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp2
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h2
-rw-r--r--src/cryptonote_core/i_core_events.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp76
-rw-r--r--src/cryptonote_core/tx_pool.h6
-rw-r--r--src/cryptonote_core/tx_sanity_check.cpp2
-rw-r--r--src/cryptonote_core/tx_sanity_check.h2
-rw-r--r--src/cryptonote_protocol/CMakeLists.txt2
-rw-r--r--src/cryptonote_protocol/block_queue.cpp2
-rw-r--r--src/cryptonote_protocol/block_queue.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h5
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl51
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler_common.h2
-rw-r--r--src/cryptonote_protocol/enums.h3
-rw-r--r--src/cryptonote_protocol/fwd.h2
-rw-r--r--src/cryptonote_protocol/levin_notify.cpp20
-rw-r--r--src/cryptonote_protocol/levin_notify.h2
-rw-r--r--src/daemon/CMakeLists.txt2
-rw-r--r--src/daemon/command_line_args.h6
-rw-r--r--src/daemon/command_parser_executor.cpp2
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp2
-rw-r--r--src/daemon/command_server.h2
-rw-r--r--src/daemon/core.h2
-rw-r--r--src/daemon/daemon.cpp74
-rw-r--r--src/daemon/daemon.h5
-rw-r--r--src/daemon/executor.cpp2
-rw-r--r--src/daemon/executor.h2
-rw-r--r--src/daemon/main.cpp24
-rw-r--r--src/daemon/p2p.h2
-rw-r--r--src/daemon/protocol.h2
-rw-r--r--src/daemon/rpc.h2
-rw-r--r--src/daemon/rpc_command_executor.cpp5
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/daemonizer/CMakeLists.txt2
-rw-r--r--src/daemonizer/daemonizer.h2
-rw-r--r--src/daemonizer/posix_daemonizer.inl2
-rw-r--r--src/daemonizer/posix_fork.h2
-rw-r--r--src/daemonizer/windows_daemonizer.inl2
-rw-r--r--src/daemonizer/windows_service.cpp2
-rw-r--r--src/daemonizer/windows_service.h2
-rw-r--r--src/daemonizer/windows_service_runner.h2
-rw-r--r--src/debug_utilities/CMakeLists.txt2
-rw-r--r--src/debug_utilities/cn_deserialize.cpp2
-rw-r--r--src/debug_utilities/dns_checks.cpp2
-rw-r--r--src/debug_utilities/object_sizes.cpp2
-rw-r--r--src/device/CMakeLists.txt3
-rw-r--r--src/device/device.cpp2
-rw-r--r--src/device/device.hpp2
-rw-r--r--src/device/device_cold.hpp2
-rw-r--r--src/device/device_default.cpp7
-rw-r--r--src/device/device_default.hpp2
-rw-r--r--src/device/device_io.hpp2
-rw-r--r--src/device/device_io_hid.cpp2
-rw-r--r--src/device/device_io_hid.hpp2
-rw-r--r--src/device/device_ledger.cpp14
-rw-r--r--src/device/device_ledger.hpp2
-rw-r--r--src/device/log.cpp2
-rw-r--r--src/device/log.hpp2
-rw-r--r--src/device_trezor/CMakeLists.txt2
-rw-r--r--src/device_trezor/device_trezor.cpp6
-rw-r--r--src/device_trezor/device_trezor.hpp2
-rw-r--r--src/device_trezor/device_trezor_base.cpp2
-rw-r--r--src/device_trezor/device_trezor_base.hpp2
-rw-r--r--src/device_trezor/trezor.hpp2
-rw-r--r--src/device_trezor/trezor/exceptions.hpp2
-rw-r--r--src/device_trezor/trezor/messages_map.cpp2
-rw-r--r--src/device_trezor/trezor/messages_map.hpp2
-rw-r--r--src/device_trezor/trezor/protocol.cpp2
-rw-r--r--src/device_trezor/trezor/protocol.hpp2
-rw-r--r--src/device_trezor/trezor/transport.cpp5
-rw-r--r--src/device_trezor/trezor/transport.hpp2
-rw-r--r--src/device_trezor/trezor/trezor_defs.hpp2
-rw-r--r--src/gen_multisig/CMakeLists.txt2
-rw-r--r--src/gen_multisig/gen_multisig.cpp2
-rw-r--r--src/gen_ssl_cert/CMakeLists.txt2
-rw-r--r--src/gen_ssl_cert/gen_ssl_cert.cpp2
-rw-r--r--src/hardforks/CMakeLists.txt2
-rw-r--r--src/hardforks/hardforks.cpp2
-rw-r--r--src/hardforks/hardforks.h2
-rw-r--r--src/mnemonics/CMakeLists.txt2
-rw-r--r--src/mnemonics/chinese_simplified.h2
-rw-r--r--src/mnemonics/dutch.h2
-rw-r--r--src/mnemonics/electrum-words.cpp2
-rw-r--r--src/mnemonics/electrum-words.h2
-rw-r--r--src/mnemonics/english.h2
-rw-r--r--src/mnemonics/english_old.h2
-rw-r--r--src/mnemonics/esperanto.h2
-rw-r--r--src/mnemonics/french.h2
-rw-r--r--src/mnemonics/german.h2
-rw-r--r--src/mnemonics/italian.h2
-rw-r--r--src/mnemonics/japanese.h2
-rw-r--r--src/mnemonics/language_base.h76
-rw-r--r--src/mnemonics/lojban.h2
-rw-r--r--src/mnemonics/portuguese.h2
-rw-r--r--src/mnemonics/russian.h2
-rw-r--r--src/mnemonics/singleton.h2
-rw-r--r--src/mnemonics/spanish.h2
-rw-r--r--src/multisig/CMakeLists.txt2
-rw-r--r--src/multisig/multisig.cpp9
-rw-r--r--src/multisig/multisig.h2
-rw-r--r--src/net/dandelionpp.cpp2
-rw-r--r--src/net/dandelionpp.h2
-rw-r--r--src/net/i2p_address.cpp2
-rw-r--r--src/net/i2p_address.h2
-rw-r--r--src/net/socks.cpp2
-rw-r--r--src/net/socks.h2
-rw-r--r--src/net/socks_connect.cpp2
-rw-r--r--src/net/socks_connect.h2
-rw-r--r--src/net/zmq.cpp16
-rw-r--r--src/net/zmq.h24
-rw-r--r--src/p2p/CMakeLists.txt2
-rw-r--r--src/p2p/net_node.cpp2
-rw-r--r--src/p2p/net_node.h2
-rw-r--r--src/p2p/net_node.inl17
-rw-r--r--src/p2p/net_node_common.h2
-rw-r--r--src/p2p/net_peerlist.h2
-rw-r--r--src/p2p/net_peerlist_boost_serialization.h2
-rw-r--r--src/p2p/p2p_protocol_defs.h2
-rw-r--r--src/p2p/stdafx.h2
-rw-r--r--src/platform/mingw/alloca.h2
-rw-r--r--src/platform/msc/alloca.h2
-rw-r--r--src/platform/msc/inline_c.h2
-rw-r--r--src/platform/msc/stdbool.h2
-rw-r--r--src/platform/msc/sys/param.h2
-rw-r--r--src/ringct/CMakeLists.txt2
-rw-r--r--src/ringct/bulletproofs.cc2
-rw-r--r--src/ringct/bulletproofs.h2
-rw-r--r--src/ringct/rctCryptoOps.c2
-rw-r--r--src/ringct/rctCryptoOps.h2
-rw-r--r--src/ringct/rctSigs.cpp5
-rw-r--r--src/ringct/rctTypes.h3
-rw-r--r--src/rpc/CMakeLists.txt24
-rw-r--r--src/rpc/core_rpc_server.cpp66
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h2
-rw-r--r--src/rpc/core_rpc_server_error_codes.h4
-rw-r--r--src/rpc/daemon_handler.cpp5
-rw-r--r--src/rpc/daemon_handler.h2
-rw-r--r--src/rpc/daemon_messages.cpp108
-rw-r--r--src/rpc/daemon_messages.h8
-rw-r--r--src/rpc/daemon_rpc_version.h2
-rw-r--r--src/rpc/fwd.h37
-rw-r--r--src/rpc/instanciations.cpp2
-rw-r--r--src/rpc/message.cpp16
-rw-r--r--src/rpc/message.h8
-rw-r--r--src/rpc/message_data_structs.h2
-rw-r--r--src/rpc/rpc_args.cpp4
-rw-r--r--src/rpc/rpc_args.h2
-rw-r--r--src/rpc/rpc_handler.h2
-rw-r--r--src/rpc/rpc_payment.cpp16
-rw-r--r--src/rpc/rpc_payment.h4
-rw-r--r--src/rpc/rpc_payment_costs.h2
-rw-r--r--src/rpc/rpc_payment_signature.cpp2
-rw-r--r--src/rpc/rpc_payment_signature.h2
-rw-r--r--src/rpc/rpc_version_str.cpp2
-rw-r--r--src/rpc/rpc_version_str.h2
-rw-r--r--src/rpc/zmq_pub.cpp478
-rw-r--r--src/rpc/zmq_pub.h110
-rw-r--r--src/rpc/zmq_server.cpp174
-rw-r--r--src/rpc/zmq_server.h25
-rw-r--r--src/serialization/CMakeLists.txt2
-rw-r--r--src/serialization/binary_archive.h2
-rw-r--r--src/serialization/binary_utils.h2
-rw-r--r--src/serialization/container.h2
-rw-r--r--src/serialization/crypto.h2
-rw-r--r--src/serialization/debug_archive.h2
-rw-r--r--src/serialization/deque.h2
-rw-r--r--src/serialization/difficulty_type.h2
-rw-r--r--src/serialization/json_archive.h2
-rw-r--r--src/serialization/json_object.cpp88
-rw-r--r--src/serialization/json_object.h106
-rw-r--r--src/serialization/json_utils.h2
-rw-r--r--src/serialization/list.h2
-rw-r--r--src/serialization/pair.h2
-rw-r--r--src/serialization/serialization.h2
-rw-r--r--src/serialization/set.h2
-rw-r--r--src/serialization/string.h2
-rw-r--r--src/serialization/unordered_set.h2
-rw-r--r--src/serialization/variant.h2
-rw-r--r--src/serialization/vector.h2
-rw-r--r--src/simplewallet/CMakeLists.txt3
-rw-r--r--src/simplewallet/simplewallet.cpp150
-rw-r--r--src/simplewallet/simplewallet.h9
-rw-r--r--src/version.cpp.in4
-rw-r--r--src/wallet/CMakeLists.txt2
-rw-r--r--src/wallet/api/CMakeLists.txt2
-rw-r--r--src/wallet/api/address_book.cpp2
-rw-r--r--src/wallet/api/address_book.h2
-rw-r--r--src/wallet/api/pending_transaction.cpp2
-rw-r--r--src/wallet/api/pending_transaction.h2
-rw-r--r--src/wallet/api/subaddress.cpp2
-rw-r--r--src/wallet/api/subaddress.h2
-rw-r--r--src/wallet/api/subaddress_account.cpp2
-rw-r--r--src/wallet/api/subaddress_account.h2
-rw-r--r--src/wallet/api/transaction_history.cpp2
-rw-r--r--src/wallet/api/transaction_history.h2
-rw-r--r--src/wallet/api/transaction_info.cpp2
-rw-r--r--src/wallet/api/transaction_info.h2
-rw-r--r--src/wallet/api/unsigned_transaction.cpp2
-rw-r--r--src/wallet/api/unsigned_transaction.h2
-rw-r--r--src/wallet/api/utils.cpp2
-rw-r--r--src/wallet/api/wallet.cpp4
-rw-r--r--src/wallet/api/wallet.h2
-rw-r--r--src/wallet/api/wallet2_api.h2
-rw-r--r--src/wallet/api/wallet_manager.cpp2
-rw-r--r--src/wallet/api/wallet_manager.h2
-rw-r--r--src/wallet/message_store.cpp103
-rw-r--r--src/wallet/message_store.h3
-rw-r--r--src/wallet/message_transporter.h1
-rw-r--r--src/wallet/node_rpc_proxy.cpp2
-rw-r--r--src/wallet/node_rpc_proxy.h2
-rw-r--r--src/wallet/wallet2.cpp170
-rw-r--r--src/wallet/wallet2.h24
-rw-r--r--src/wallet/wallet_args.cpp2
-rw-r--r--src/wallet/wallet_args.h2
-rw-r--r--src/wallet/wallet_errors.h2
-rw-r--r--src/wallet/wallet_rpc_helpers.h2
-rw-r--r--src/wallet/wallet_rpc_payments.cpp2
-rw-r--r--src/wallet/wallet_rpc_server.cpp11
-rw-r--r--src/wallet/wallet_rpc_server.h2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h8
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h2
-rw-r--r--tests/CMakeLists.txt39
-rw-r--r--tests/benchmark.cpp437
-rw-r--r--tests/benchmark.h.in5
-rw-r--r--tests/block_weight/block_weight.cpp2
-rwxr-xr-xtests/block_weight/block_weight.py2
-rw-r--r--tests/core_proxy/CMakeLists.txt2
-rw-r--r--tests/core_proxy/core_proxy.cpp3
-rw-r--r--tests/core_proxy/core_proxy.h2
-rw-r--r--tests/core_tests/CMakeLists.txt2
-rw-r--r--tests/core_tests/block_reward.cpp2
-rw-r--r--tests/core_tests/block_reward.h2
-rw-r--r--tests/core_tests/block_validation.cpp2
-rw-r--r--tests/core_tests/block_validation.h2
-rw-r--r--tests/core_tests/bulletproofs.cpp2
-rw-r--r--tests/core_tests/bulletproofs.h2
-rw-r--r--tests/core_tests/chain_split_1.cpp2
-rw-r--r--tests/core_tests/chain_split_1.h2
-rw-r--r--tests/core_tests/chain_switch_1.cpp2
-rw-r--r--tests/core_tests/chain_switch_1.h2
-rw-r--r--tests/core_tests/chaingen.cpp2
-rw-r--r--tests/core_tests/chaingen.h7
-rw-r--r--tests/core_tests/chaingen001.cpp2
-rw-r--r--tests/core_tests/chaingen_main.cpp2
-rw-r--r--tests/core_tests/chaingen_tests_list.h2
-rw-r--r--tests/core_tests/double_spend.cpp2
-rw-r--r--tests/core_tests/double_spend.h2
-rw-r--r--tests/core_tests/double_spend.inl2
-rw-r--r--tests/core_tests/integer_overflow.cpp2
-rw-r--r--tests/core_tests/integer_overflow.h2
-rw-r--r--tests/core_tests/multisig.cpp2
-rw-r--r--tests/core_tests/multisig.h2
-rw-r--r--tests/core_tests/rct.cpp2
-rw-r--r--tests/core_tests/rct.h2
-rw-r--r--tests/core_tests/ring_signature_1.cpp2
-rw-r--r--tests/core_tests/ring_signature_1.h2
-rw-r--r--tests/core_tests/transaction_tests.cpp2
-rw-r--r--tests/core_tests/transaction_tests.h2
-rw-r--r--tests/core_tests/tx_pool.cpp2
-rw-r--r--tests/core_tests/tx_pool.h2
-rw-r--r--tests/core_tests/tx_validation.cpp2
-rw-r--r--tests/core_tests/tx_validation.h2
-rw-r--r--tests/core_tests/v2_tests.cpp2
-rw-r--r--tests/core_tests/v2_tests.h2
-rw-r--r--tests/crypto/CMakeLists.txt2
-rw-r--r--tests/crypto/cnv4-jit.c2
-rw-r--r--tests/crypto/crypto-ops-data.c2
-rw-r--r--tests/crypto/crypto-ops.c2
-rw-r--r--tests/crypto/crypto-tests.h2
-rw-r--r--tests/crypto/crypto.cpp2
-rw-r--r--tests/crypto/hash.c2
-rw-r--r--tests/crypto/main.cpp2
-rw-r--r--tests/crypto/random.c2
-rw-r--r--tests/cryptolib.pl2
-rw-r--r--tests/cryptotest.pl2
-rw-r--r--tests/daemon_tests/CMakeLists.txt2
-rw-r--r--tests/daemon_tests/transfers.cpp2
-rw-r--r--tests/data/fuzz/tx-extra/TXEXTRA1bin0 -> 44 bytes
-rw-r--r--tests/data/fuzz/tx-extra/TXEXTRA2bin0 -> 547 bytes
-rw-r--r--tests/difficulty/CMakeLists.txt2
-rw-r--r--tests/difficulty/difficulty.cpp2
-rwxr-xr-xtests/difficulty/generate-data2
-rw-r--r--tests/functional_tests/CMakeLists.txt2
-rwxr-xr-xtests/functional_tests/address_book.py12
-rwxr-xr-xtests/functional_tests/bans.py2
-rwxr-xr-xtests/functional_tests/cold_signing.py2
-rwxr-xr-xtests/functional_tests/functional_tests_rpc.py14
-rwxr-xr-xtests/functional_tests/get_output_distribution.py2
-rwxr-xr-xtests/functional_tests/integrated_address.py2
-rw-r--r--tests/functional_tests/main.cpp2
-rw-r--r--tests/functional_tests/make_test_signature.cc2
-rwxr-xr-xtests/functional_tests/multisig.py2
-rwxr-xr-xtests/functional_tests/proofs.py41
-rwxr-xr-xtests/functional_tests/rpc_payment.py2
-rwxr-xr-xtests/functional_tests/sign_message.py2
-rwxr-xr-xtests/functional_tests/speed.py4
-rw-r--r--tests/functional_tests/transactions_flow_test.cpp2
-rw-r--r--tests/functional_tests/transactions_flow_test.h2
-rw-r--r--tests/functional_tests/transactions_generation_from_blockchain.cpp2
-rw-r--r--tests/functional_tests/transactions_generation_from_blockchain.h2
-rwxr-xr-xtests/functional_tests/transfer.py54
-rwxr-xr-xtests/functional_tests/txpool.py37
-rwxr-xr-xtests/functional_tests/uri.py2
-rwxr-xr-xtests/functional_tests/validate_address.py6
-rwxr-xr-xtests/functional_tests/wallet.py2
-rw-r--r--tests/fuzz/CMakeLists.txt56
-rw-r--r--tests/fuzz/base58.cpp51
-rw-r--r--tests/fuzz/block.cpp38
-rw-r--r--tests/fuzz/bulletproof.cpp41
-rw-r--r--tests/fuzz/cold-outputs.cpp82
-rw-r--r--tests/fuzz/cold-transaction.cpp84
-rw-r--r--tests/fuzz/fuzzer.cpp6
-rw-r--r--tests/fuzz/fuzzer.h110
-rw-r--r--tests/fuzz/http-client.cpp51
-rw-r--r--tests/fuzz/levin.cpp51
-rw-r--r--tests/fuzz/load_from_binary.cpp50
-rw-r--r--tests/fuzz/load_from_json.cpp50
-rw-r--r--tests/fuzz/parse_url.cpp50
-rw-r--r--tests/fuzz/signature.cpp69
-rw-r--r--tests/fuzz/transaction.cpp38
-rw-r--r--tests/fuzz/tx-extra.cpp40
-rw-r--r--tests/hash-target.cpp2
-rw-r--r--tests/hash/CMakeLists.txt2
-rw-r--r--tests/hash/main.cpp2
-rw-r--r--tests/io.h2
-rw-r--r--tests/libwallet_api_tests/CMakeLists.txt2
-rw-r--r--tests/libwallet_api_tests/main.cpp2
-rw-r--r--tests/net_load_tests/CMakeLists.txt2
-rw-r--r--tests/net_load_tests/clt.cpp2
-rw-r--r--tests/net_load_tests/net_load_tests.h2
-rw-r--r--tests/net_load_tests/srv.cpp2
-rw-r--r--tests/performance_tests/CMakeLists.txt2
-rw-r--r--tests/performance_tests/bulletproof.h2
-rw-r--r--tests/performance_tests/check_hash.h2
-rw-r--r--tests/performance_tests/check_tx_signature.h2
-rw-r--r--tests/performance_tests/cn_fast_hash.h2
-rw-r--r--tests/performance_tests/cn_slow_hash.h2
-rw-r--r--tests/performance_tests/construct_tx.h2
-rw-r--r--tests/performance_tests/crypto_ops.h2
-rw-r--r--tests/performance_tests/derive_public_key.h2
-rw-r--r--tests/performance_tests/derive_secret_key.h2
-rw-r--r--tests/performance_tests/equality.h4
-rw-r--r--tests/performance_tests/ge_frombytes_vartime.h2
-rw-r--r--tests/performance_tests/ge_tobytes.h2
-rw-r--r--tests/performance_tests/generate_key_derivation.h2
-rw-r--r--tests/performance_tests/generate_key_image.h2
-rw-r--r--tests/performance_tests/generate_key_image_helper.h2
-rw-r--r--tests/performance_tests/generate_keypair.h2
-rw-r--r--tests/performance_tests/is_out_to_acc.h2
-rw-r--r--tests/performance_tests/main.cpp2
-rw-r--r--tests/performance_tests/multi_tx_test_base.h2
-rw-r--r--tests/performance_tests/performance_tests.h4
-rw-r--r--tests/performance_tests/performance_utils.h2
-rw-r--r--tests/performance_tests/range_proof.h2
-rw-r--r--tests/performance_tests/rct_mlsag.h2
-rw-r--r--tests/performance_tests/sc_reduce32.h2
-rw-r--r--tests/performance_tests/signature.h2
-rw-r--r--tests/performance_tests/single_tx_test_base.h2
-rw-r--r--tests/performance_tests/subaddress_expand.h2
-rw-r--r--tests/unit_tests/CMakeLists.txt4
-rw-r--r--tests/unit_tests/account.cpp36
-rw-r--r--tests/unit_tests/address_from_url.cpp2
-rw-r--r--tests/unit_tests/apply_permutation.cpp2
-rw-r--r--tests/unit_tests/base58.cpp2
-rw-r--r--tests/unit_tests/block_queue.cpp2
-rw-r--r--tests/unit_tests/block_reward.cpp2
-rw-r--r--tests/unit_tests/blockchain_db.cpp2
-rw-r--r--tests/unit_tests/bulletproofs.cpp2
-rw-r--r--tests/unit_tests/canonical_amounts.cpp2
-rw-r--r--tests/unit_tests/chacha.cpp2
-rw-r--r--tests/unit_tests/checkpoints.cpp2
-rw-r--r--tests/unit_tests/command_line.cpp2
-rw-r--r--tests/unit_tests/crypto.cpp2
-rw-r--r--tests/unit_tests/decompose_amount_into_digits.cpp2
-rw-r--r--tests/unit_tests/difficulty.cpp2
-rw-r--r--tests/unit_tests/dns_resolver.cpp2
-rw-r--r--tests/unit_tests/epee_boosted_tcp_server.cpp2
-rw-r--r--tests/unit_tests/epee_levin_protocol_handler_async.cpp2
-rw-r--r--tests/unit_tests/epee_utils.cpp310
-rw-r--r--tests/unit_tests/fee.cpp2
-rw-r--r--tests/unit_tests/get_xtype_from_string.cpp2
-rw-r--r--tests/unit_tests/hardfork.cpp2
-rw-r--r--tests/unit_tests/hashchain.cpp2
-rw-r--r--tests/unit_tests/http.cpp2
-rw-r--r--tests/unit_tests/json_serialization.cpp27
-rw-r--r--tests/unit_tests/json_serialization.h42
-rw-r--r--tests/unit_tests/levin.cpp256
-rw-r--r--tests/unit_tests/logging.cpp2
-rw-r--r--tests/unit_tests/long_term_block_weight.cpp2
-rw-r--r--tests/unit_tests/main.cpp2
-rw-r--r--tests/unit_tests/memwipe.cpp2
-rw-r--r--tests/unit_tests/mnemonics.cpp4
-rw-r--r--tests/unit_tests/mul_div.cpp2
-rw-r--r--tests/unit_tests/multisig.cpp2
-rw-r--r--tests/unit_tests/node_server.cpp2
-rw-r--r--tests/unit_tests/output_selection.cpp2
-rw-r--r--tests/unit_tests/parse_amount.cpp2
-rw-r--r--tests/unit_tests/ringct.cpp2
-rw-r--r--tests/unit_tests/rolling_median.cpp2
-rw-r--r--tests/unit_tests/rpc_version_str.cpp2
-rw-r--r--tests/unit_tests/serialization.cpp42
-rw-r--r--tests/unit_tests/sha256.cpp2
-rw-r--r--tests/unit_tests/slow_memmem.cpp2
-rw-r--r--tests/unit_tests/subaddress.cpp2
-rw-r--r--tests/unit_tests/test_peerlist.cpp2
-rw-r--r--tests/unit_tests/test_protocol_pack.cpp2
-rw-r--r--tests/unit_tests/test_tx_utils.cpp2
-rw-r--r--tests/unit_tests/tx_proof.cpp130
-rw-r--r--tests/unit_tests/unbound.cpp2
-rw-r--r--tests/unit_tests/unit_tests_utils.h2
-rw-r--r--tests/unit_tests/uri.cpp2
-rw-r--r--tests/unit_tests/varint.cpp2
-rw-r--r--tests/unit_tests/vercmp.cpp2
-rw-r--r--tests/unit_tests/zmq_rpc.cpp722
-rw-r--r--translations/CMakeLists.txt2
-rw-r--r--translations/generate_translations_header.c2
-rw-r--r--utils/build_scripts/windows.bat2
-rw-r--r--utils/gpg_keys/rbrunner7.asc31
-rw-r--r--utils/munin_plugins/alt_blocks_count2
-rw-r--r--utils/munin_plugins/difficulty2
-rw-r--r--utils/munin_plugins/grey_peerlist_size2
-rw-r--r--utils/munin_plugins/height2
-rw-r--r--utils/munin_plugins/incoming_connections_count2
-rw-r--r--utils/munin_plugins/outgoing_connections_count2
-rw-r--r--utils/munin_plugins/tx_count2
-rw-r--r--utils/munin_plugins/tx_pool_size2
-rw-r--r--utils/munin_plugins/white_peerlist_size2
-rw-r--r--utils/systemd/monerod.service2
640 files changed, 7820 insertions, 2128 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7d506d817..aaad0c3a6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -20,9 +20,9 @@ jobs:
- uses: actions/checkout@v1
with:
submodules: recursive
- - uses: numworks/setup-msys2@v1
- - name: update pacman
- run: msys2do pacman -Syu --noconfirm
+ - uses: eine/setup-msys2@v0
+ with:
+ update: true
- name: install monero dependencies
run: msys2do pacman -S --noconfirm mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb git
- name: build
diff --git a/.gitmodules b/.gitmodules
index f8e7c305b..9dacf534f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -15,3 +15,7 @@
[submodule "external/randomx"]
path = external/randomx
url = https://github.com/tevador/RandomX
+[submodule "external/supercop"]
+ path = external/supercop
+ url = https://github.com/monero-project/supercop
+ branch = monero
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d9ec866e4..51e497260 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -31,7 +31,7 @@
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
list(INSERT CMAKE_MODULE_PATH 0
- "${CMAKE_SOURCE_DIR}/cmake")
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(CheckLinkerFlag)
@@ -48,7 +48,12 @@ message(STATUS "CMake version ${CMAKE_VERSION}")
project(monero)
-include(FindCcache) # Has to be included after the project() macro, to be able to read the CXX variable.
+option (USE_CCACHE "Use ccache if a usable instance is found" ON)
+if (USE_CCACHE)
+ include(FindCcache) # Has to be included after the project() macro, to be able to read the CXX variable.
+else()
+ message(STATUS "ccache deselected")
+endif()
enable_language(C ASM)
@@ -205,6 +210,7 @@ if(NOT MANUAL_SUBMODULES)
check_submodule(external/rapidjson)
check_submodule(external/trezor-common)
check_submodule(external/randomx)
+ check_submodule(external/supercop)
endif()
endif()
@@ -262,6 +268,12 @@ else()
endif()
option(BUILD_DEBUG_UTILITIES "Build debug utilities." DEFAULT_BUILD_DEBUG_UTILITIES)
+if(OSSFUZZ)
+ message(STATUS "Using OSS-Fuzz fuzzing system")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DOSSFUZZ")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOSSFUZZ")
+endif()
+
# Check whether we're on a 32-bit or 64-bit system
if(CMAKE_SIZEOF_VOID_P EQUAL "8")
set(DEFAULT_BUILD_64 ON)
@@ -300,7 +312,7 @@ endif()
# elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*")
# set(BSDI TRUE)
-include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external)
+include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include)
if(APPLE)
include_directories(SYSTEM /usr/include/malloc)
@@ -445,6 +457,9 @@ add_definition_if_function_found(strptime HAVE_STRPTIME)
add_definitions(-DAUTO_INITIALIZE_EASYLOGGINGPP)
+set(MONERO_GENERATED_HEADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated_include")
+include_directories(${MONERO_GENERATED_HEADERS_DIR})
+
# Generate header for embedded translations
# Generate header for embedded translations, use target toolchain if depends, otherwise use the
# lrelease and lupdate binaries from the host
@@ -646,7 +661,8 @@ else()
endif()
# linker
- if (NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1)))
+ if (NOT SANITIZE AND NOT OSSFUZZ AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1)))
+ # PIE executables randomly crash at startup with ASAN
# Windows binaries die on startup with PIE when compiled with GCC <9.x
add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS)
endif()
@@ -768,7 +784,8 @@ else()
endif(ARM)
- if(ANDROID AND NOT BUILD_GUI_DEPS STREQUAL "ON" OR IOS)
+ # random crash on startup when asan is on if pie is enabled
+ if(NOT SANITIZE AND ANDROID AND NOT BUILD_GUI_DEPS STREQUAL "ON" OR IOS)
#From Android 5: "only position independent executables (PIE) are supported"
message(STATUS "Enabling PIE executable")
set(PIC_FLAG "")
@@ -974,6 +991,7 @@ if(SODIUM_LIBRARY)
set(ZMQ_LIB "${ZMQ_LIB};${SODIUM_LIBRARY}")
endif()
+include(external/supercop/functions.cmake) # place after setting flags and before src directory inclusion
add_subdirectory(contrib)
add_subdirectory(src)
diff --git a/CMakeLists_IOS.txt b/CMakeLists_IOS.txt
index 3b7eacc8a..951286cb0 100644
--- a/CMakeLists_IOS.txt
+++ b/CMakeLists_IOS.txt
@@ -1,4 +1,4 @@
-# Portions Copyright (c) 2017-2019, The Monero Project
+# Portions Copyright (c) 2017-2020, The Monero Project
# This file is based off of the https://code.google.com/archive/p/ios-cmake/
# It has been altered for Monero iOS development
#
diff --git a/LICENSE b/LICENSE
index 7035c2324..7b9b36420 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2014-2019, The Monero Project
+Copyright (c) 2014-2020, The Monero Project
All rights reserved.
diff --git a/Makefile b/Makefile
index 2c7bd20a9..928942721 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/README.md b/README.md
index ce193a034..46e592106 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Monero
-Copyright (c) 2014-2019 The Monero Project.
+Copyright (c) 2014-2020 The Monero Project.
Portions Copyright (c) 2012-2013 The Cryptonote developers.
## Table of Contents
@@ -90,7 +90,7 @@ As with many development projects, the repository on Github is considered to be
Monero is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Both Monero and Bitcoin donations can be made to **donate.getmonero.org** if using a client that supports the [OpenAlias](https://openalias.org) standard. Alternatively you can send XMR to the Monero donation address via the `donate` command (type `help` in the command-line wallet for details).
-The Monero donation address is: `44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A` (viewkey: `f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`)
+The Monero donation address is: `888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H` (viewkey: `f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`)
The Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H`
@@ -132,7 +132,7 @@ Dates are provided in the format YYYY-MM-DD.
| 1686275 | 2018-10-19 | v9 | v0.13.0.0 | v0.13.0.4 | bulletproofs required
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
-| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.15.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
+| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
X's indicate that these details have not been determined as of commit date.
@@ -194,8 +194,8 @@ Install all dependencies at once on Debian/Ubuntu:
Install all dependencies at once on macOS with the provided Brewfile:
``` brew update && brew bundle --file=contrib/brew/Brewfile ```
-FreeBSD one liner for required to build dependencies
-```pkg install git gmake cmake pkgconf boost-libs libzmq libsodium```
+FreeBSD 12.1 one-liner required to build dependencies:
+```pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium```
### Cloning the repository
@@ -219,7 +219,7 @@ invokes cmake commands as needed.
```bash
cd monero
- git checkout release-v0.15
+ git checkout release-v0.16
make
```
@@ -292,7 +292,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```bash
git clone https://github.com/monero-project/monero.git
cd monero
- git checkout tags/v0.15.0.0
+ git checkout tags/v0.16.0.0
```
* Build:
@@ -409,10 +409,10 @@ application.
cd monero
```
-* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.15.0.0'. If you don't care about the version and just want binaries from master, skip this step:
+* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.16.0.0'. If you don't care about the version and just want binaries from master, skip this step:
```bash
- git checkout v0.15.0.0
+ git checkout v0.16.0.0
```
* If you are on a 64-bit system, run:
diff --git a/ZMQ.md b/ZMQ.md
new file mode 100644
index 000000000..9128ff2ad
--- /dev/null
+++ b/ZMQ.md
@@ -0,0 +1,61 @@
+# The Current/Future Status of ZMQ in Monero
+
+## ZMQ Pub/Sub
+Client `ZMQ_SUB` sockets must "subscribe" to topics before it receives any data.
+This allows filtering on the server side, so network traffic is reduced. Monero
+allows for filtering on: (1) format, (2) context, and (3) event.
+
+ * **format** refers to the _wire_ format (i.e. JSON) used to send event
+ information.
+ * **context** allows for a reduction in fields for the event, so the
+ daemon doesn't waste cycles serializing fields that get ignored.
+ * **event** refers to status changes occurring within the daemon (i.e. new
+ block to main chain).
+
+ * Formats:
+ * `json`
+ * Contexts:
+ * `full` - the entire block or transaction is transmitted (the hash can be
+ computed remotely).
+ * `minimal` - the bare minimum for a remote client to react to an event is
+ sent.
+ * Events:
+ * `chain_main` - changes to the primary/main blockchain.
+ * `txpool_add` - new _publicly visible_ transactions in the mempool.
+ Includes previously unseen transactions in a block but _not_ the
+ `miner_tx`. Does not "re-publish" after a reorg. Includes `do_not_relay`
+ transactions.
+
+The subscription topics are formatted as `format-context-event`, with prefix
+matching supported by both Monero and ZMQ. The `format`, `context` and `event`
+will _never_ have hyphens or colons in their name. For example, subscribing to
+`json-minimal-chain_main` will send minimal information in JSON when changes
+to the main/primary blockchain occur. Whereas, subscribing to `json-minimal`
+will send minimal information in JSON on all available events supported by the
+daemon.
+
+The Monero daemon will ensure that events prefixed by `chain` will be sent in
+"chain-order" - the `prev_id` (hash) field will _always_ refer to a previous
+block. On rollbacks/reorgs, the event will reference an earlier block in the
+chain instead of the last block. The Monero daemon also ensures that
+`txpool_add` events are sent before `chain_*` events - the `chain_*` messages
+will only serialize miner transactions since the other transactions were
+previously published via `txpool_add`. This prevents transactions from being
+serialized twice, even when the transaction was first observed in a block.
+
+ZMQ Pub/Sub will drop messages if the network is congested, so the above rules
+for send order are used for detecting lost messages. A missing gap in `height`
+or `prev_id` for `chain_*` events indicates a lost pub message. Missing
+`txpool_add` messages can only be detected at the next `chain_` message.
+
+Since blockchain events can be dropped, clients will likely want to have a
+timeout against `chain_main` events. The `GetLastBlockHeader` RPC is useful
+for checking the current chain state. Dropped messages should be rare in most
+conditions.
+
+The Monero daemon will send a `txpool_add` pub exactly once for each
+transaction, even after a reorg or restarts. Clients should use the
+`GetTransactionPool` after a reorg to get all transactions that have been put
+back into the tx pool or been invalidated due to a double-spend.
+
+
diff --git a/cmake/32-bit-toolchain.cmake b/cmake/32-bit-toolchain.cmake
index 2d53adf06..6bee56482 100644
--- a/cmake/32-bit-toolchain.cmake
+++ b/cmake/32-bit-toolchain.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/cmake/64-bit-toolchain.cmake b/cmake/64-bit-toolchain.cmake
index 7c56eef95..5eaa17596 100644
--- a/cmake/64-bit-toolchain.cmake
+++ b/cmake/64-bit-toolchain.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/cmake/FindCcache.cmake b/cmake/FindCcache.cmake
index fa357610b..a0734a312 100644
--- a/cmake/FindCcache.cmake
+++ b/cmake/FindCcache.cmake
@@ -41,17 +41,20 @@
find_program(CCACHE_FOUND ccache)
if (CCACHE_FOUND)
- set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp")
+ # Try to compile a test program with ccache, in order to verify if it really works. (needed on exotic setups)
+ # Create a temporary file with a simple program.
+ set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp")
file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }")
+ # And run the found ccache on it.
execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET)
if (${RET} EQUAL 0)
- message("found usable ccache: ${CCACHE_FOUND}")
+ # Success
+ message(STATUS "Found usable ccache: ${CCACHE_FOUND}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_FOUND}")
else()
- message("found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}")
- endif()
+ message(STATUS "Found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}")
+ endif()
else()
- message("ccache NOT found!")
+ message(STATUS "ccache NOT found! Please install it for faster rebuilds.")
endif()
-
diff --git a/cmake/FindUnbound.cmake b/cmake/FindUnbound.cmake
index e3eb3d67e..65c6725c6 100644
--- a/cmake/FindUnbound.cmake
+++ b/cmake/FindUnbound.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake
index 7eaf3ddf1..3263266c7 100644
--- a/cmake/GitVersion.cmake
+++ b/cmake/GitVersion.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/cmake/Version.cmake b/cmake/Version.cmake
index 26c2e2a1d..a6c13ab6c 100644
--- a/cmake/Version.cmake
+++ b/cmake/Version.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/cmake/test-libusb-version.c b/cmake/test-libusb-version.c
index b80191b58..bd8f90c03 100644
--- a/cmake/test-libusb-version.c
+++ b/cmake/test-libusb-version.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/cmake/test-protobuf.cpp b/cmake/test-protobuf.cpp
index 0a1ca82be..4b2e19725 100644
--- a/cmake/test-protobuf.cpp
+++ b/cmake/test-protobuf.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/cmake/test-static-assert.c b/cmake/test-static-assert.c
index 2e6c84839..520939c6f 100644
--- a/cmake/test-static-assert.c
+++ b/cmake/test-static-assert.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/cmake/test-static-assert.cpp b/cmake/test-static-assert.cpp
index 2e6c84839..520939c6f 100644
--- a/cmake/test-static-assert.cpp
+++ b/cmake/test-static-assert.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt
index 0db645ce9..511f0416e 100644
--- a/contrib/CMakeLists.txt
+++ b/contrib/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/contrib/codefresh/codefresh.yml b/contrib/codefresh/codefresh.yml
deleted file mode 100644
index a22debfa1..000000000
--- a/contrib/codefresh/codefresh.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-version: '1.0'
-steps:
- init_submodules:
- title: Init Submodules
- commands:
- - git submodule update --init --recursive
- image: codefreshio/git-image:latest
- working_directory: ${{main_clone}}
-
- BuildingDockerImage:
- title: Building Docker Image
- type: build
- image_name: monero
- working_directory: ./
- tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
- dockerfile: Dockerfile
- build_arguments:
- - NPROC=1
diff --git a/contrib/depends/toolchain.cmake.in b/contrib/depends/toolchain.cmake.in
index 2634423ab..422d9dede 100644
--- a/contrib/depends/toolchain.cmake.in
+++ b/contrib/depends/toolchain.cmake.in
@@ -1,5 +1,6 @@
# Set the system name to one of Android, Darwin, FreeBSD, Linux, or Windows
SET(CMAKE_SYSTEM_NAME @depends@)
+SET(CMAKE_SYSTEM_PROCESSOR @arch@)
SET(CMAKE_BUILD_TYPE @release_type@)
OPTION(STATIC "Link libraries statically" ON)
@@ -63,14 +64,14 @@ set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Find programs on host
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # Find libs in target
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Find includes in target
-set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR} CACHE STRING "" FORCE)
-
# specify the cross compiler to be used. Darwin uses clang provided by the SDK.
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
SET(CMAKE_C_COMPILER @prefix@/native/bin/clang)
SET(CMAKE_C_COMPILER_TARGET x86_64-apple-darwin11)
SET(CMAKE_CXX_COMPILER @prefix@/native/bin/clang++ -stdlib=libc++)
SET(CMAKE_CXX_COMPILER_TARGET x86_64-apple-darwin11)
+ SET(CMAKE_ASM_COMPILER_TARGET x86_64-apple-darwin11)
+ SET(CMAKE_ASM-ATT_COMPILER_TARGET x86_64-apple-darwin11)
SET(_CMAKE_TOOLCHAIN_PREFIX x86_64-apple-darwin11-)
SET(APPLE True)
SET(BUILD_TAG "mac-x64")
diff --git a/contrib/epee/CMakeLists.txt b/contrib/epee/CMakeLists.txt
index a2c636304..6e303eb0b 100644
--- a/contrib/epee/CMakeLists.txt
+++ b/contrib/epee/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/contrib/epee/include/byte_slice.h b/contrib/epee/include/byte_slice.h
index bd9452b11..6b79f6d92 100644
--- a/contrib/epee/include/byte_slice.h
+++ b/contrib/epee/include/byte_slice.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -39,6 +39,7 @@
namespace epee
{
struct byte_slice_data;
+ class byte_stream;
struct release_byte_slice
{
@@ -50,6 +51,12 @@ namespace epee
}
};
+ //! Frees ref count + buffer allocated internally by `byte_buffer`.
+ struct release_byte_buffer
+ {
+ void operator()(std::uint8_t* buf) const noexcept;
+ };
+
/*! Inspired by slices in golang. Storage is thread-safe reference counted,
allowing for cheap copies or range selection on the bytes. The bytes
owned by this class are always immutable.
@@ -104,6 +111,9 @@ namespace epee
//! Convert `buffer` into a slice using one allocation for shared count.
explicit byte_slice(std::string&& buffer);
+ //! Convert `stream` into a slice with zero allocations.
+ explicit byte_slice(byte_stream&& stream) noexcept;
+
byte_slice(byte_slice&& source) noexcept;
~byte_slice() noexcept = default;
@@ -149,5 +159,19 @@ namespace epee
//! \post `empty()` \return Ownership of ref-counted buffer.
std::unique_ptr<byte_slice_data, release_byte_slice> take_buffer() noexcept;
};
+
+ //! Alias for a buffer that has space for a `byte_slice` ref count.
+ using byte_buffer = std::unique_ptr<std::uint8_t, release_byte_buffer>;
+
+ /*! \return `buf` with a new size of exactly `length`. New bytes not
+ initialized. A `nullptr` is returned on allocation failure. */
+ byte_buffer byte_buffer_resize(byte_buffer buf, std::size_t length) noexcept;
+
+ /*! Increase `buf` of size `current` by `more` bytes.
+
+ \throw std::range_error if `current + more` exceeds `size_t` bounds.
+ \return Buffer of `current + more` bytes. A `nullptr` is returned on
+ allocation failure. */
+ byte_buffer byte_buffer_increase(byte_buffer buf, std::size_t current, std::size_t more);
} // epee
diff --git a/contrib/epee/include/byte_stream.h b/contrib/epee/include/byte_stream.h
new file mode 100644
index 000000000..98f563ca9
--- /dev/null
+++ b/contrib/epee/include/byte_stream.h
@@ -0,0 +1,224 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+#include "byte_slice.h"
+#include "span.h"
+
+namespace epee
+{
+ /*! \brief A partial drop-in replacement for `std::ostream`.
+
+ Only a few base `std::ostream` functions are implemented - enough for
+ rapidjson output currently.
+
+ Advantages over `std::stringstream` or `rapidjson::StringBuffer`:
+ - The internal buffer can be taken without a copy.
+ - The internal buffer can be given to `byte_slice` with zero
+ allocations for reference count.
+ - The internal buffer can be given to `zmq_msg_data_init` without a
+ copy or extra allocation.
+ an additional advantage over `std::stringstream`:
+ - Construction is significantly faster - the global `std::locale`
+ does not have to be acquired (global thread synchronization), and
+ an extra allocation for `std::stringbuf` is not needed (which is an
+ addition to the buffer inside of that object). */
+ class byte_stream
+ {
+ byte_buffer buffer_; //! Beginning of buffer
+ std::uint8_t* next_write_; //! Current write position
+ const std::uint8_t* end_; //! End of buffer
+ std::size_t increase_size_; //! Minimum buffer size increase
+
+ //! \post `requested <= available()`
+ void overflow(const std::size_t requested);
+
+ //! Ensures that at least `requested` bytes are available.
+ void check(const std::size_t requested)
+ {
+ const std::size_t remaining = available();
+ if (remaining < requested)
+ overflow(requested);
+ }
+
+ public:
+ using char_type = std::uint8_t;
+ using Ch = char_type;
+
+ //! \return Default minimum size increase on buffer overflow
+ static constexpr std::size_t default_increase() noexcept { return 4096; }
+
+ //! Increase internal buffer by at least `byte_stream_increase` bytes.
+ byte_stream() noexcept
+ : byte_stream(default_increase())
+ {}
+
+ //! Increase internal buffer by at least `increase` bytes.
+ explicit byte_stream(const std::size_t increase) noexcept
+ : buffer_(nullptr),
+ next_write_(nullptr),
+ end_(nullptr),
+ increase_size_(increase)
+ {}
+
+ byte_stream(byte_stream&& rhs) noexcept;
+ ~byte_stream() noexcept = default;
+ byte_stream& operator=(byte_stream&& rhs) noexcept;
+
+ //! \return The minimum increase size on buffer overflow
+ std::size_t increase_size() const noexcept { return increase_size_; }
+
+ const std::uint8_t* data() const noexcept { return buffer_.get(); }
+ std::uint8_t* tellp() const noexcept { return next_write_; }
+ std::size_t available() const noexcept { return end_ - next_write_; }
+ std::size_t size() const noexcept { return next_write_ - buffer_.get(); }
+ std::size_t capacity() const noexcept { return end_ - buffer_.get(); }
+
+ //! Compatibility with rapidjson.
+ void Flush() const noexcept
+ {}
+
+ /*! Reserve at least `more` bytes.
+ \post `size() + more <= available()`.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void reserve(const std::size_t more)
+ {
+ check(more);
+ }
+
+ /*! Copy `length` bytes starting at `ptr` to end of stream.
+ \throw std::range_error If exceeding max size_t value.
+ \throw std::bad_alloc If allocation fails. */
+ void write(const std::uint8_t* ptr, const std::size_t length)
+ {
+ check(length);
+ std::memcpy(tellp(), ptr, length);
+ next_write_ += length;
+ }
+
+ /*! Copy `length` bytes starting at `ptr` to end of stream.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void write(const char* ptr, const std::size_t length)
+ {
+ write(reinterpret_cast<const std::uint8_t*>(ptr), length);
+ }
+
+ /*! Copy `source` to end of stream.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void write(const epee::span<const std::uint8_t> source)
+ {
+ write(source.data(), source.size());
+ }
+
+ /*! Copy `source` to end of stream.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void write(const epee::span<const char> source)
+ {
+ write(source.data(), source.size());
+ }
+
+ /*! Copy `ch` to end of stream.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void put(const std::uint8_t ch)
+ {
+ check(1);
+ put_unsafe(ch);
+ }
+
+ /*! Copy `ch` to end of stream. Provides rapidjson compatability.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void Put(const std::uint8_t ch)
+ {
+ put(ch);
+ }
+
+ /*! Writes `ch` to end of stream without runtime capacity checks. Must use
+ `reserve` before calling this function. Primarily for use with
+ rapidjson, which writes characters at a time but reserves memory in
+ blocks. Most applications want to use `put` or `write`. */
+ void put_unsafe(const std::uint8_t ch) noexcept
+ {
+ assert(1 <= available());
+ *(tellp()) = ch;
+ ++next_write_;
+ }
+
+ /*! Write `ch` to end of stream `count` times.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void put_n(const std::uint8_t ch, const std::size_t count)
+ {
+ check(count);
+ std::memset(tellp(), count, ch);
+ next_write_ += count;
+ }
+
+ /*! Copy `ch` to end of stream.
+ \throw std::range_error if exceeding max `size_t` value.
+ \throw std::bad_alloc if allocation fails. */
+ void push_back(const std::uint8_t ch)
+ {
+ put(ch);
+ }
+
+ //! \return The internal buffer. \post `size() == capacity() == 0`.
+ byte_buffer take_buffer() noexcept;
+ };
+
+ //! Compatability/optimization for rapidjson.
+
+ inline void PutReserve(byte_stream& dest, const std::size_t length)
+ {
+ dest.reserve(length);
+ }
+
+ //! Compatability/optimization for rapidjson.
+
+ inline void PutUnsafe(byte_stream& dest, const std::uint8_t ch)
+ {
+ dest.put_unsafe(ch);
+ }
+
+ //! Compability/optimization for rapidjson.
+ inline void PutN(byte_stream& dest, const std::uint8_t ch, const std::size_t count)
+ {
+ dest.put_n(ch, count);
+ }
+} // epee
+
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h
index a7788aeb8..08d9b8802 100644
--- a/contrib/epee/include/console_handler.h
+++ b/contrib/epee/include/console_handler.h
@@ -465,7 +465,7 @@ eof:
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, std::function<std::string(void)> prompt, const std::string& usage = "")
{
async_console_handler console_handler;
- return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), prompt, usage);
+ return console_handler.run(ptsrv, std::bind<bool>(no_srv_param_adapter<t_server, t_handler>, std::placeholders::_1, std::placeholders::_2, handlr), prompt, usage);
}
template<class t_server, class t_handler>
@@ -634,7 +634,7 @@ eof:
bool run_handling(std::function<std::string(void)> prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
{
- return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string, exit_handler);
+ return m_console_handler.run(std::bind(&console_handlers_binder::process_command_str, this, std::placeholders::_1), prompt, usage_string, exit_handler);
}
void print_prompt()
diff --git a/contrib/epee/include/int-util.h b/contrib/epee/include/int-util.h
index dcd58a8c4..bc422d841 100644
--- a/contrib/epee/include/int-util.h
+++ b/contrib/epee/include/int-util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/md5_l.inl b/contrib/epee/include/md5_l.inl
index 8e339e006..cb2bd54f9 100644
--- a/contrib/epee/include/md5_l.inl
+++ b/contrib/epee/include/md5_l.inl
@@ -277,7 +277,7 @@ namespace md5
/* Zeroize sensitive information.
*/
- MD5_memset ((POINTER)context, 0, sizeof (*context));
+ memwipe ((POINTER)context, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
@@ -369,7 +369,7 @@ namespace md5
/* Zeroize sensitive information.
*/
- MD5_memset ((POINTER)x, 0, sizeof (x));
+ memwipe ((POINTER)x, sizeof (x));
}
/* Note: Replace "for loop" with standard memcpy if possible.
@@ -431,9 +431,9 @@ namespace md5
MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
/* scrub the pads and key context (if used) */
- MD5_memset( (POINTER)&k_ipad, 0, sizeof(k_ipad));
- MD5_memset( (POINTER)&k_opad, 0, sizeof(k_opad));
- MD5_memset( (POINTER)&tk, 0, sizeof(tk));
+ memwipe( (POINTER)&k_ipad, sizeof(k_ipad));
+ memwipe( (POINTER)&k_opad, sizeof(k_opad));
+ memwipe( (POINTER)&tk, sizeof(tk));
/* and we're done. */
}
@@ -459,7 +459,7 @@ namespace md5
state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
}
- MD5_memset( (POINTER)&hmac, 0, sizeof(hmac));
+ memwipe( (POINTER)&hmac, sizeof(hmac));
}
diff --git a/contrib/epee/include/memwipe.h b/contrib/epee/include/memwipe.h
index d586608cb..c6e8f072c 100644
--- a/contrib/epee/include/memwipe.h
+++ b/contrib/epee/include/memwipe.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index 3a2c5341d..3c31cf22b 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -48,12 +48,9 @@
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/array.hpp>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp> //! \TODO Convert to std::shared_ptr
#include <boost/enable_shared_from_this.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/thread/thread.hpp>
-#include <memory>
#include "byte_slice.h"
#include "net_utils_base.h"
#include "syncobj.h"
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 43ede3cc1..cbacd118c 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -32,7 +32,6 @@
-#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/chrono.hpp>
@@ -210,15 +209,15 @@ PRAGMA_WARNING_DISABLE_VS(4355)
socket().async_receive(boost::asio::buffer(buffer_),
boost::asio::socket_base::message_peek,
strand_.wrap(
- boost::bind(&connection<t_protocol_handler>::handle_receive, self,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
+ std::bind(&connection<t_protocol_handler>::handle_receive, self,
+ std::placeholders::_1,
+ std::placeholders::_2)));
else
async_read_some(boost::asio::buffer(buffer_),
strand_.wrap(
- boost::bind(&connection<t_protocol_handler>::handle_read, self,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
+ std::bind(&connection<t_protocol_handler>::handle_read, self,
+ std::placeholders::_1,
+ std::placeholders::_2)));
#if !defined(_WIN32) || !defined(__i686)
// not supported before Windows7, too lazy for runtime check
// Just exclude for 32bit windows builds
@@ -688,7 +687,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
reset_timer(get_default_timeout(), false);
async_write(boost::asio::buffer(m_send_que.front().data(), size_now ) ,
strand_.wrap(
- boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
+ std::bind(&connection<t_protocol_handler>::handle_write, self, std::placeholders::_1, std::placeholders::_2)
)
);
//_dbg3("(chunk): " << size_now);
@@ -892,7 +891,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), void(), "Unexpected queue size");
async_write(boost::asio::buffer(m_send_que.front().data(), size_now) ,
strand_.wrap(
- boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2)
+ std::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), std::placeholders::_1, std::placeholders::_2)
)
);
//_dbg3("(normal)" << size_now);
@@ -1402,7 +1401,7 @@ POP_WARNINGS
shared_context->connect_mut.lock(); shared_context->ec = ec_; shared_context->cond.notify_one(); shared_context->connect_mut.unlock();
};
- sock_.async_connect(remote_endpoint, boost::bind<void>(connect_callback, _1, local_shared_context));
+ sock_.async_connect(remote_endpoint, std::bind<void>(connect_callback, std::placeholders::_1, local_shared_context));
while(local_shared_context->ec == boost::asio::error::would_block)
{
bool r = local_shared_context->cond.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(conn_timeout));
diff --git a/contrib/epee/include/net/connection_basic.hpp b/contrib/epee/include/net/connection_basic.hpp
index 2f60f7604..90303a785 100644
--- a/contrib/epee/include/net/connection_basic.hpp
+++ b/contrib/epee/include/net/connection_basic.hpp
@@ -8,7 +8,7 @@
// ! (how ever if in some wonderful juristdictions that is not the case, then why not make another sub-class withat that members and licence it as epee part)
// ! Working on above premise, IF this is valid in your juristdictions, then consider this code as released as:
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/net/http_auth.h b/contrib/epee/include/net/http_auth.h
index 00b9750b7..b7105bf8a 100644
--- a/contrib/epee/include/net/http_auth.h
+++ b/contrib/epee/include/net/http_auth.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h
index 6cd19f17b..d88b53c94 100644
--- a/contrib/epee/include/net/http_server_impl_base.h
+++ b/contrib/epee/include/net/http_server_impl_base.h
@@ -31,7 +31,7 @@
#include <boost/thread.hpp>
-#include <boost/bind.hpp>
+#include <boost/bind/bind.hpp>
#include "net/abstract_tcp_server2.h"
#include "http_protocol_handler.h"
diff --git a/contrib/epee/include/net/net_fwd.h b/contrib/epee/include/net/net_fwd.h
index ba4fe6259..f5b6f8db4 100644
--- a/contrib/epee/include/net/net_fwd.h
+++ b/contrib/epee/include/net/net_fwd.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/net/network_throttle-detail.hpp b/contrib/epee/include/net/network_throttle-detail.hpp
index 353ae0c0c..0bab4fe9e 100644
--- a/contrib/epee/include/net/network_throttle-detail.hpp
+++ b/contrib/epee/include/net/network_throttle-detail.hpp
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer in monero.cc project)
/// @brief implementaion for throttling of connection (count and rate-limit speed etc)
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/net/network_throttle.hpp b/contrib/epee/include/net/network_throttle.hpp
index 02a286326..b6f7592c2 100644
--- a/contrib/epee/include/net/network_throttle.hpp
+++ b/contrib/epee/include/net/network_throttle.hpp
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer in monero.cc project)
/// @brief interface for throttling of connection (count and rate-limit speed etc)
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -44,10 +44,7 @@
#include <boost/shared_ptr.hpp>
#include <atomic>
-#include <boost/asio.hpp>
#include <boost/array.hpp>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/thread/thread.hpp>
@@ -63,7 +60,6 @@
#include <boost/utility/value_init.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include <boost/thread/thread.hpp>
#include "misc_language.h"
#include "pragma_comp_defs.h"
#include <sstream>
diff --git a/contrib/epee/include/rolling_median.h b/contrib/epee/include/rolling_median.h
index 8b5a82a84..11275aa70 100644
--- a/contrib/epee/include/rolling_median.h
+++ b/contrib/epee/include/rolling_median.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h
index 59895535f..b355c960a 100644
--- a/contrib/epee/include/span.h
+++ b/contrib/epee/include/span.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index b18e04a27..4633fa546 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -28,6 +28,7 @@
#include "portable_storage_template_helper.h"
#include <boost/utility/value_init.hpp>
+#include <functional>
#include "span.h"
#include "net/levin_base.h"
@@ -294,20 +295,20 @@ namespace epee
#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \
if(!is_notify && command_id == command) \
- {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
#define HANDLE_INVOKE_T2(COMMAND, func) \
if(!is_notify && COMMAND::ID == command) \
- {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
#define HANDLE_NOTIFY2(command_id, func, type_name_in) \
if(is_notify && command_id == command) \
- {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
#define HANDLE_NOTIFY_T2(NOTIFY, func) \
if(is_notify && NOTIFY::ID == command) \
- {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
#define CHAIN_INVOKE_MAP2(func) \
diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h
index 2256f6b83..5a6cc0b51 100644
--- a/contrib/epee/include/storages/parserse_base_utils.h
+++ b/contrib/epee/include/storages/parserse_base_utils.h
@@ -196,7 +196,7 @@ namespace misc_utils
uint32_t dst = 0;
for (int i = 0; i < 4; ++i)
{
- const unsigned char tmp = isx[(int)*++it];
+ const unsigned char tmp = isx[(unsigned char)*++it];
CHECK_AND_ASSERT_THROW_MES(tmp != 0xff, "Bad Unicode encoding");
dst = dst << 4 | tmp;
}
diff --git a/contrib/epee/include/storages/portable_storage_bin_utils.h b/contrib/epee/include/storages/portable_storage_bin_utils.h
index bcde64487..b2b4bc56c 100644
--- a/contrib/epee/include/storages/portable_storage_bin_utils.h
+++ b/contrib/epee/include/storages/portable_storage_bin_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/include/wipeable_string.h b/contrib/epee/include/wipeable_string.h
index f0e526b92..22c30855f 100644
--- a/contrib/epee/include/wipeable_string.h
+++ b/contrib/epee/include/wipeable_string.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index 88018d71a..8adf69162 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -26,8 +26,9 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-add_library(epee STATIC byte_slice.cpp hex.cpp abstract_http_client.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp
- levin_base.cpp memwipe.c connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp
+
+add_library(epee STATIC byte_slice.cpp byte_stream.cpp hex.cpp abstract_http_client.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp
+ wipeable_string.cpp levin_base.cpp memwipe.c connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp
int-util.cpp)
if (USE_READLINE AND (GNU_READLINE_FOUND OR (DEPENDS AND NOT MINGW)))
diff --git a/contrib/epee/src/byte_slice.cpp b/contrib/epee/src/byte_slice.cpp
index 3ad3b3e7e..faf7689be 100644
--- a/contrib/epee/src/byte_slice.cpp
+++ b/contrib/epee/src/byte_slice.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,6 +34,7 @@
#include <utility>
#include "byte_slice.h"
+#include "byte_stream.h"
namespace epee
{
@@ -117,6 +118,12 @@ namespace epee
}
} // anonymous
+ void release_byte_buffer::operator()(std::uint8_t* buf) const noexcept
+ {
+ if (buf)
+ std::free(buf - sizeof(raw_byte_slice));
+ }
+
byte_slice::byte_slice(byte_slice_data* storage, span<const std::uint8_t> portion) noexcept
: storage_(storage), portion_(portion)
{
@@ -126,10 +133,13 @@ namespace epee
template<typename T>
byte_slice::byte_slice(const adapt_buffer, T&& buffer)
- : storage_(nullptr), portion_(to_byte_span(to_span(buffer)))
+ : storage_(nullptr), portion_(nullptr)
{
if (!buffer.empty())
+ {
storage_ = allocate_slice<adapted_byte_slice<T>>(0, std::move(buffer));
+ portion_ = to_byte_span(to_span(static_cast<adapted_byte_slice<T> *>(storage_.get())->buffer));
+ }
}
byte_slice::byte_slice(std::initializer_list<span<const std::uint8_t>> sources)
@@ -163,6 +173,19 @@ namespace epee
: byte_slice(adapt_buffer{}, std::move(buffer))
{}
+ byte_slice::byte_slice(byte_stream&& stream) noexcept
+ : storage_(nullptr), portion_(stream.data(), stream.size())
+ {
+ if (stream.size())
+ {
+ std::uint8_t* const data = stream.take_buffer().release() - sizeof(raw_byte_slice);
+ new (data) raw_byte_slice{};
+ storage_.reset(reinterpret_cast<raw_byte_slice*>(data));
+ }
+ else
+ portion_ = nullptr;
+ }
+
byte_slice::byte_slice(byte_slice&& source) noexcept
: storage_(std::move(source.storage_)), portion_(source.portion_)
{
@@ -190,14 +213,17 @@ namespace epee
byte_slice byte_slice::take_slice(const std::size_t max_bytes) noexcept
{
byte_slice out{};
- std::uint8_t const* const ptr = data();
- out.portion_ = {ptr, portion_.remove_prefix(max_bytes)};
- if (portion_.empty())
- out.storage_ = std::move(storage_); // no atomic inc/dec
- else
- out = {storage_.get(), out.portion_};
+ if (max_bytes)
+ {
+ std::uint8_t const* const ptr = data();
+ out.portion_ = {ptr, portion_.remove_prefix(max_bytes)};
+ if (portion_.empty())
+ out.storage_ = std::move(storage_); // no atomic inc/dec
+ else
+ out = {storage_.get(), out.portion_};
+ }
return out;
}
@@ -217,4 +243,29 @@ namespace epee
portion_ = nullptr;
return out;
}
+
+ byte_buffer byte_buffer_resize(byte_buffer buf, const std::size_t length) noexcept
+ {
+ if (std::numeric_limits<std::size_t>::max() - sizeof(raw_byte_slice) < length)
+ return nullptr;
+
+ std::uint8_t* data = buf.get();
+ if (data != nullptr)
+ data -= sizeof(raw_byte_slice);
+
+ data = static_cast<std::uint8_t*>(std::realloc(data, sizeof(raw_byte_slice) + length));
+ if (data == nullptr)
+ return nullptr;
+
+ buf.release();
+ buf.reset(data + sizeof(raw_byte_slice));
+ return buf;
+ }
+
+ byte_buffer byte_buffer_increase(byte_buffer buf, const std::size_t current, const std::size_t more)
+ {
+ if (std::numeric_limits<std::size_t>::max() - current < more)
+ throw std::range_error{"byte_buffer_increase size_t overflow"};
+ return byte_buffer_resize(std::move(buf), current + more);
+ }
} // epee
diff --git a/contrib/epee/src/byte_stream.cpp b/contrib/epee/src/byte_stream.cpp
new file mode 100644
index 000000000..e87d9f0bc
--- /dev/null
+++ b/contrib/epee/src/byte_stream.cpp
@@ -0,0 +1,93 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "byte_stream.h"
+
+#include <algorithm>
+#include <limits>
+#include <utility>
+
+#include <iostream>
+
+namespace epee
+{
+ void byte_stream::overflow(const std::size_t requested)
+ {
+ // Recalculating `need` bytes removes at least one instruction from every
+ // inlined `put` call in header
+
+ assert(available() < requested);
+ const std::size_t need = requested - available();
+
+ const std::size_t len = size();
+ const std::size_t cap = capacity();
+ const std::size_t increase = std::max(need, increase_size());
+
+ next_write_ = nullptr;
+ end_ = nullptr;
+
+ buffer_ = byte_buffer_increase(std::move(buffer_), cap, increase);
+ if (!buffer_)
+ throw std::bad_alloc{};
+
+ next_write_ = buffer_.get() + len;
+ end_ = buffer_.get() + cap + increase;
+ }
+
+ byte_stream::byte_stream(byte_stream&& rhs) noexcept
+ : buffer_(std::move(rhs.buffer_)),
+ next_write_(rhs.next_write_),
+ end_(rhs.end_),
+ increase_size_(rhs.increase_size_)
+ {
+ rhs.next_write_ = nullptr;
+ rhs.end_ = nullptr;
+ }
+
+ byte_stream& byte_stream::operator=(byte_stream&& rhs) noexcept
+ {
+ if (this != std::addressof(rhs))
+ {
+ buffer_ = std::move(rhs.buffer_);
+ next_write_ = rhs.next_write_;
+ end_ = rhs.end_;
+ increase_size_ = rhs.increase_size_;
+ rhs.next_write_ = nullptr;
+ rhs.end_ = nullptr;
+ }
+ return *this;
+ }
+
+ byte_buffer byte_stream::take_buffer() noexcept
+ {
+ byte_buffer out{std::move(buffer_)};
+ next_write_ = nullptr;
+ end_ = nullptr;
+ return out;
+ }
+}
diff --git a/contrib/epee/src/connection_basic.cpp b/contrib/epee/src/connection_basic.cpp
index 3ce7a1057..30efbf2fc 100644
--- a/contrib/epee/src/connection_basic.cpp
+++ b/contrib/epee/src/connection_basic.cpp
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer in monero.cc project)
/// @brief base for connection, contains e.g. the ratelimit hooks
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/http_auth.cpp b/contrib/epee/src/http_auth.cpp
index 5f4907cc2..18ee18bd4 100644
--- a/contrib/epee/src/http_auth.cpp
+++ b/contrib/epee/src/http_auth.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/int-util.cpp b/contrib/epee/src/int-util.cpp
index e9d0822e0..061c90b4e 100644
--- a/contrib/epee/src/int-util.cpp
+++ b/contrib/epee/src/int-util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/levin_base.cpp b/contrib/epee/src/levin_base.cpp
index ff845e2a7..5ec86b3d6 100644
--- a/contrib/epee/src/levin_base.cpp
+++ b/contrib/epee/src/levin_base.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/memwipe.c b/contrib/epee/src/memwipe.c
index ad1ef510d..41a6b36ac 100644
--- a/contrib/epee/src/memwipe.c
+++ b/contrib/epee/src/memwipe.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp
index e96bf627f..bcde215be 100644
--- a/contrib/epee/src/mlog.cpp
+++ b/contrib/epee/src/mlog.cpp
@@ -100,7 +100,7 @@ static const char *get_default_categories(int level)
switch (level)
{
case 0:
- categories = "*:WARNING,net:FATAL,net.http:FATAL,net.ssl:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,serialization:FATAL,daemon.rpc.payment:ERROR,stacktrace:INFO,logging:INFO,msgwriter:INFO";
+ categories = "*:WARNING,net:FATAL,net.http:FATAL,net.ssl:FATAL,net.p2p:FATAL,net.cn:FATAL,daemon.rpc:FATAL,global:INFO,verify:FATAL,serialization:FATAL,daemon.rpc.payment:ERROR,stacktrace:INFO,logging:INFO,msgwriter:INFO";
break;
case 1:
categories = "*:INFO,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO,perf.*:DEBUG";
diff --git a/contrib/epee/src/net_ssl.cpp b/contrib/epee/src/net_ssl.cpp
index 2cf9ea2b6..a09e82771 100644
--- a/contrib/epee/src/net_ssl.cpp
+++ b/contrib/epee/src/net_ssl.cpp
@@ -511,7 +511,7 @@ bool ssl_options_t::handshake(
// autodetect will reconnect without SSL - warn and keep connection encrypted
if (support != ssl_support_t::e_ssl_support_autodetect)
{
- MERROR("SSL certificate is not in the allowed list, connection droppped");
+ MERROR("SSL certificate is not in the allowed list, connection dropped");
return false;
}
MWARNING("SSL peer has not been verified");
diff --git a/contrib/epee/src/network_throttle-detail.cpp b/contrib/epee/src/network_throttle-detail.cpp
index 72544cbf6..f4ebeabf0 100644
--- a/contrib/epee/src/network_throttle-detail.cpp
+++ b/contrib/epee/src/network_throttle-detail.cpp
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer in monero.cc project)
/// @brief implementaion for throttling of connection (count and rate-limit speed etc)
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/network_throttle.cpp b/contrib/epee/src/network_throttle.cpp
index f4f0b2c46..b2c861e30 100644
--- a/contrib/epee/src/network_throttle.cpp
+++ b/contrib/epee/src/network_throttle.cpp
@@ -26,7 +26,7 @@ Throttling work by:
*/
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/epee/src/wipeable_string.cpp b/contrib/epee/src/wipeable_string.cpp
index 4928db172..21312d49d 100644
--- a/contrib/epee/src/wipeable_string.cpp
+++ b/contrib/epee/src/wipeable_string.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md
index c09786c36..c0f230887 100644
--- a/contrib/gitian/README.md
+++ b/contrib/gitian/README.md
@@ -126,7 +126,7 @@ Setup for LXC:
```bash
GH_USER=fluffypony
-VERSION=v0.15.0.0
+VERSION=v0.16.0.0
./gitian-build.py --setup $GH_USER $VERSION
```
@@ -182,7 +182,7 @@ If you chose to do detached signing using `--detach-sign` above (recommended), y
```bash
GH_USER=fluffypony
-VERSION=v0.15.0.0
+VERSION=v0.16.0.0
gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert
gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert
diff --git a/contrib/gitian/gitian-android.yml b/contrib/gitian/gitian-android.yml
index 02614b1a5..de98efafe 100644
--- a/contrib/gitian/gitian-android.yml
+++ b/contrib/gitian/gitian-android.yml
@@ -1,5 +1,5 @@
---
-name: "monero-android-0.15"
+name: "monero-android-0.16"
enable_cache: true
suites:
- "bionic"
diff --git a/contrib/gitian/gitian-freebsd.yml b/contrib/gitian/gitian-freebsd.yml
index 0220b82a5..e97c3802b 100644
--- a/contrib/gitian/gitian-freebsd.yml
+++ b/contrib/gitian/gitian-freebsd.yml
@@ -1,5 +1,5 @@
---
-name: "monero-freebsd-0.15"
+name: "monero-freebsd-0.16"
enable_cache: true
suites:
- "bionic"
diff --git a/contrib/gitian/gitian-linux.yml b/contrib/gitian/gitian-linux.yml
index 9c2ebac9b..bd42637aa 100644
--- a/contrib/gitian/gitian-linux.yml
+++ b/contrib/gitian/gitian-linux.yml
@@ -1,5 +1,5 @@
---
-name: "monero-linux-0.15"
+name: "monero-linux-0.16"
enable_cache: true
suites:
- "bionic"
diff --git a/contrib/gitian/gitian-osx.yml b/contrib/gitian/gitian-osx.yml
index ecc7d4b59..4d44c4845 100644
--- a/contrib/gitian/gitian-osx.yml
+++ b/contrib/gitian/gitian-osx.yml
@@ -1,5 +1,5 @@
---
-name: "monero-osx-0.15"
+name: "monero-osx-0.16"
enable_cache: true
suites:
- "bionic"
diff --git a/contrib/gitian/gitian-win.yml b/contrib/gitian/gitian-win.yml
index bd85695c1..196b6ebbe 100644
--- a/contrib/gitian/gitian-win.yml
+++ b/contrib/gitian/gitian-win.yml
@@ -1,5 +1,5 @@
---
-name: "monero-win-0.15"
+name: "monero-win-0.16"
enable_cache: true
suites:
- "bionic"
diff --git a/contrib/snap/monerod-wrapper b/contrib/snap/monerod-wrapper
deleted file mode 100755
index f7266e11c..000000000
--- a/contrib/snap/monerod-wrapper
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-if [ ! -d "$SNAP_USER_DATA/etc" ]; then
- mkdir $SNAP_USER_DATA/etc/
- cp -R $SNAP/etc/monerod.conf $SNAP_USER_DATA/etc/monerod.conf
-fi
-
-exec "$SNAP/bin/monerod" "$@"
diff --git a/contrib/snap/monerod.conf b/contrib/snap/monerod.conf
deleted file mode 100644
index 1078e73b2..000000000
--- a/contrib/snap/monerod.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-# Configuration for monerod
-# Syntax: any command line option may be specified as 'clioptionname=value'.
-# Boolean options such as 'no-igd' are specified as 'no-igd=1'.
-# See 'monerod --help' for all available options.
-
-# Overridden by snap:
-# data-dir=/var/lib/monero
-# log-file=/var/log/monero/monero.log
-
-log-level=0
diff --git a/contrib/snap/setup/gui/icon.png b/contrib/snap/setup/gui/icon.png
deleted file mode 100644
index b7e821270..000000000
--- a/contrib/snap/setup/gui/icon.png
+++ /dev/null
Binary files differ
diff --git a/contrib/snap/snapcraft.yaml b/contrib/snap/snapcraft.yaml
deleted file mode 100644
index b3b75d278..000000000
--- a/contrib/snap/snapcraft.yaml
+++ /dev/null
@@ -1,78 +0,0 @@
-name: monero
-version: 0.11.1.0-1
-summary: "Monero: the secure, private, untraceable cryptocurrency https://getmonero.org"
-description: |
- Monero is a private, secure, untraceable, decentralised digital currency.
- You are your bank, you control your funds, and nobody can trace your transfers
- unless you allow them to do so.
-grade: devel
-confinement: strict
-
-apps:
- monerod:
- daemon: forking
- command: |
- monerod-wrapper --detach --data-dir ${SNAP_COMMON} --config-file ${SNAP_USER_DATA}/etc/monerod.conf
- plugs:
- - network
- - network-bind
- monero-wallet-rpc:
- command: |
- monero-wallet-rpc --log-file ${SNAP_USER_DATA}
- plugs:
- - home
- - network
- - network-bind
- monero-wallet-cli:
- command: |
- monero-wallet-cli --log-file ${SNAP_USER_DATA}
- plugs:
- - home
- - network
-
-parts:
- cmake-build:
- plugin: cmake
- configflags:
- - -DBDB_STATIC=1
- - -DBoost_USE_STATIC_LIBS=1
- - -DBoost_USE_STATIC_RUNTIME=1
- - -DARCH=default
- source: .
- build-packages:
- - gcc
- - pkg-config
- - libunbound-dev
- - libevent-dev
- - libboost-all-dev
- - libzmqpp-dev
- - libzmq3-dev
- - libsodium-dev
- - libdb-dev
- - libunwind-dev
- - libminiupnpc-dev
- - libldns-dev
- - libexpat1-dev
- - libreadline6-dev
- - bison
- - doxygen
- - graphviz
- stage-packages:
- - libminiupnpc10
- - libunbound2
- - libunwind8
- prime:
- - bin
- - usr/lib/
- - -usr/lib/gcc
- - -usr/share
-
- dist-files:
- plugin: dump
- source: .
- organize:
- contrib/snap/monerod.conf: etc/monerod.conf
- contrib/snap/monerod-wrapper: bin/monerod-wrapper
- prime:
- - etc
- - bin
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index 71b165f4f..a8916a7d0 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -80,4 +80,5 @@ endif()
add_subdirectory(db_drivers)
add_subdirectory(easylogging++)
+add_subdirectory(qrcodegen)
add_subdirectory(randomx EXCLUDE_FROM_ALL)
diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc
index 8439bec0b..0d748c225 100644
--- a/external/easylogging++/easylogging++.cc
+++ b/external/easylogging++/easylogging++.cc
@@ -2475,6 +2475,100 @@ void DefaultLogDispatchCallback::handle(const LogDispatchData* data) {
}
}
+
+template<typename Transform>
+static inline std::string utf8canonical(const std::string &s, Transform t = [](wint_t c)->wint_t { return c; })
+{
+ std::string sc = "";
+ size_t avail = s.size();
+ const char *ptr = s.data();
+ wint_t cp = 0;
+ int bytes = 1;
+ char wbuf[8], *wptr;
+ while (avail--)
+ {
+ if ((*ptr & 0x80) == 0)
+ {
+ cp = *ptr++;
+ bytes = 1;
+ }
+ else if ((*ptr & 0xe0) == 0xc0)
+ {
+ if (avail < 1)
+ throw std::runtime_error("Invalid UTF-8");
+ cp = (*ptr++ & 0x1f) << 6;
+ cp |= *ptr++ & 0x3f;
+ --avail;
+ bytes = 2;
+ }
+ else if ((*ptr & 0xf0) == 0xe0)
+ {
+ if (avail < 2)
+ throw std::runtime_error("Invalid UTF-8");
+ cp = (*ptr++ & 0xf) << 12;
+ cp |= (*ptr++ & 0x3f) << 6;
+ cp |= *ptr++ & 0x3f;
+ avail -= 2;
+ bytes = 3;
+ }
+ else if ((*ptr & 0xf8) == 0xf0)
+ {
+ if (avail < 3)
+ throw std::runtime_error("Invalid UTF-8");
+ cp = (*ptr++ & 0x7) << 18;
+ cp |= (*ptr++ & 0x3f) << 12;
+ cp |= (*ptr++ & 0x3f) << 6;
+ cp |= *ptr++ & 0x3f;
+ avail -= 3;
+ bytes = 4;
+ }
+ else
+ throw std::runtime_error("Invalid UTF-8");
+
+ cp = t(cp);
+ if (cp <= 0x7f)
+ bytes = 1;
+ else if (cp <= 0x7ff)
+ bytes = 2;
+ else if (cp <= 0xffff)
+ bytes = 3;
+ else if (cp <= 0x10ffff)
+ bytes = 4;
+ else
+ throw std::runtime_error("Invalid code point UTF-8 transformation");
+
+ wptr = wbuf;
+ switch (bytes)
+ {
+ case 1: *wptr++ = cp; break;
+ case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
+ case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
+ case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
+ default: throw std::runtime_error("Invalid UTF-8");
+ }
+ *wptr = 0;
+ sc.append(wbuf, bytes);
+ cp = 0;
+ bytes = 1;
+ }
+ return sc;
+}
+
+void sanitize(std::string &s)
+{
+ s = utf8canonical(s, [](wint_t c)->wint_t {
+ if (c == 9 || c == 10 || c == 13)
+ return c;
+ if (c < 0x20)
+ return '?';
+ if (c == 0x7f)
+ return '?';
+ if (c >= 0x80 && c <= 0x9f)
+ return '?';
+ return c;
+ });
+}
+
void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix, base::type::string_t&& rawLinePayload, base::type::string_t&& logLine) {
if (m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog) {
if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
@@ -2506,6 +2600,8 @@ void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix,
m_data->logMessage()->logger()->logBuilder()->setColor(el::base::utils::colorFromLevel(level), false);
ELPP_COUT << rawLinePrefix;
m_data->logMessage()->logger()->logBuilder()->setColor(color == el::Color::Default ? el::base::utils::colorFromLevel(level): color, color != el::Color::Default);
+ try { sanitize(rawLinePayload); }
+ catch (const std::exception &e) { rawLinePayload = "<Invalid UTF-8 in log>"; }
ELPP_COUT << rawLinePayload;
m_data->logMessage()->logger()->logBuilder()->setColor(el::Color::Default, false);
ELPP_COUT << std::flush;
diff --git a/external/qrcodegen/CMakeLists.txt b/external/qrcodegen/CMakeLists.txt
new file mode 100644
index 000000000..a9060e3e8
--- /dev/null
+++ b/external/qrcodegen/CMakeLists.txt
@@ -0,0 +1,7 @@
+project(libqrcodegen)
+
+add_library(qrcodegen STATIC QrCode.cpp)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+
+target_include_directories(qrcodegen PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/external/qrcodegen/QrCode.cpp b/external/qrcodegen/QrCode.cpp
new file mode 100644
index 000000000..b9de86215
--- /dev/null
+++ b/external/qrcodegen/QrCode.cpp
@@ -0,0 +1,862 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * Copyright (c) Project Nayuki. (MIT License)
+ * https://www.nayuki.io/page/qr-code-generator-library
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * - The Software is provided "as is", without warranty of any kind, express or
+ * implied, including but not limited to the warranties of merchantability,
+ * fitness for a particular purpose and noninfringement. In no event shall the
+ * authors or copyright holders be liable for any claim, damages or other
+ * liability, whether in an action of contract, tort or otherwise, arising from,
+ * out of or in connection with the Software or the use or other dealings in the
+ * Software.
+ */
+
+#include <algorithm>
+#include <climits>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+#include <stdexcept>
+#include <utility>
+#include "QrCode.hpp"
+
+using std::int8_t;
+using std::uint8_t;
+using std::size_t;
+using std::vector;
+
+
+namespace qrcodegen {
+
+QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
+ modeBits(mode) {
+ numBitsCharCount[0] = cc0;
+ numBitsCharCount[1] = cc1;
+ numBitsCharCount[2] = cc2;
+}
+
+
+int QrSegment::Mode::getModeBits() const {
+ return modeBits;
+}
+
+
+int QrSegment::Mode::numCharCountBits(int ver) const {
+ return numBitsCharCount[(ver + 7) / 17];
+}
+
+
+const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
+const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
+const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
+const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
+const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
+
+
+QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
+ if (data.size() > static_cast<unsigned int>(INT_MAX))
+ throw std::length_error("Data too long");
+ BitBuffer bb;
+ for (uint8_t b : data)
+ bb.appendBits(b, 8);
+ return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb));
+}
+
+
+QrSegment QrSegment::makeNumeric(const char *digits) {
+ BitBuffer bb;
+ int accumData = 0;
+ int accumCount = 0;
+ int charCount = 0;
+ for (; *digits != '\0'; digits++, charCount++) {
+ char c = *digits;
+ if (c < '0' || c > '9')
+ throw std::domain_error("String contains non-numeric characters");
+ accumData = accumData * 10 + (c - '0');
+ accumCount++;
+ if (accumCount == 3) {
+ bb.appendBits(static_cast<uint32_t>(accumData), 10);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 or 2 digits remaining
+ bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1);
+ return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
+}
+
+
+QrSegment QrSegment::makeAlphanumeric(const char *text) {
+ BitBuffer bb;
+ int accumData = 0;
+ int accumCount = 0;
+ int charCount = 0;
+ for (; *text != '\0'; text++, charCount++) {
+ const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
+ if (temp == nullptr)
+ throw std::domain_error("String contains unencodable characters in alphanumeric mode");
+ accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET);
+ accumCount++;
+ if (accumCount == 2) {
+ bb.appendBits(static_cast<uint32_t>(accumData), 11);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 character remaining
+ bb.appendBits(static_cast<uint32_t>(accumData), 6);
+ return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
+}
+
+
+vector<QrSegment> QrSegment::makeSegments(const char *text) {
+ // Select the most efficient segment encoding automatically
+ vector<QrSegment> result;
+ if (*text == '\0'); // Leave result empty
+ else if (isNumeric(text))
+ result.push_back(makeNumeric(text));
+ else if (isAlphanumeric(text))
+ result.push_back(makeAlphanumeric(text));
+ else {
+ vector<uint8_t> bytes;
+ for (; *text != '\0'; text++)
+ bytes.push_back(static_cast<uint8_t>(*text));
+ result.push_back(makeBytes(bytes));
+ }
+ return result;
+}
+
+
+QrSegment QrSegment::makeEci(long assignVal) {
+ BitBuffer bb;
+ if (assignVal < 0)
+ throw std::domain_error("ECI assignment value out of range");
+ else if (assignVal < (1 << 7))
+ bb.appendBits(static_cast<uint32_t>(assignVal), 8);
+ else if (assignVal < (1 << 14)) {
+ bb.appendBits(2, 2);
+ bb.appendBits(static_cast<uint32_t>(assignVal), 14);
+ } else if (assignVal < 1000000L) {
+ bb.appendBits(6, 3);
+ bb.appendBits(static_cast<uint32_t>(assignVal), 21);
+ } else
+ throw std::domain_error("ECI assignment value out of range");
+ return QrSegment(Mode::ECI, 0, std::move(bb));
+}
+
+
+QrSegment::QrSegment(Mode md, int numCh, const std::vector<bool> &dt) :
+ mode(md),
+ numChars(numCh),
+ data(dt) {
+ if (numCh < 0)
+ throw std::domain_error("Invalid value");
+}
+
+
+QrSegment::QrSegment(Mode md, int numCh, std::vector<bool> &&dt) :
+ mode(md),
+ numChars(numCh),
+ data(std::move(dt)) {
+ if (numCh < 0)
+ throw std::domain_error("Invalid value");
+}
+
+
+int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
+ int result = 0;
+ for (const QrSegment &seg : segs) {
+ int ccbits = seg.mode.numCharCountBits(version);
+ if (seg.numChars >= (1L << ccbits))
+ return -1; // The segment's length doesn't fit the field's bit width
+ if (4 + ccbits > INT_MAX - result)
+ return -1; // The sum will overflow an int type
+ result += 4 + ccbits;
+ if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result))
+ return -1; // The sum will overflow an int type
+ result += static_cast<int>(seg.data.size());
+ }
+ return result;
+}
+
+
+bool QrSegment::isAlphanumeric(const char *text) {
+ for (; *text != '\0'; text++) {
+ if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr)
+ return false;
+ }
+ return true;
+}
+
+
+bool QrSegment::isNumeric(const char *text) {
+ for (; *text != '\0'; text++) {
+ char c = *text;
+ if (c < '0' || c > '9')
+ return false;
+ }
+ return true;
+}
+
+
+QrSegment::Mode QrSegment::getMode() const {
+ return mode;
+}
+
+
+int QrSegment::getNumChars() const {
+ return numChars;
+}
+
+
+const std::vector<bool> &QrSegment::getData() const {
+ return data;
+}
+
+
+const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
+
+
+
+int QrCode::getFormatBits(Ecc ecl) {
+ switch (ecl) {
+ case Ecc::LOW : return 1;
+ case Ecc::MEDIUM : return 0;
+ case Ecc::QUARTILE: return 3;
+ case Ecc::HIGH : return 2;
+ default: throw std::logic_error("Assertion error");
+ }
+}
+
+
+QrCode QrCode::encodeText(const char *text, Ecc ecl) {
+ vector<QrSegment> segs = QrSegment::makeSegments(text);
+ return encodeSegments(segs, ecl);
+}
+
+
+QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
+ vector<QrSegment> segs{QrSegment::makeBytes(data)};
+ return encodeSegments(segs, ecl);
+}
+
+
+QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
+ int minVersion, int maxVersion, int mask, bool boostEcl) {
+ if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
+ throw std::invalid_argument("Invalid value");
+
+ // Find the minimal version number to use
+ int version, dataUsedBits;
+ for (version = minVersion; ; version++) {
+ int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
+ dataUsedBits = QrSegment::getTotalBits(segs, version);
+ if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
+ break; // This version number is found to be suitable
+ if (version >= maxVersion) { // All versions in the range could not fit the given data
+ std::ostringstream sb;
+ if (dataUsedBits == -1)
+ sb << "Segment too long";
+ else {
+ sb << "Data length = " << dataUsedBits << " bits, ";
+ sb << "Max capacity = " << dataCapacityBits << " bits";
+ }
+ throw data_too_long(sb.str());
+ }
+ }
+ if (dataUsedBits == -1)
+ throw std::logic_error("Assertion error");
+
+ // Increase the error correction level while the data still fits in the current version number
+ for (Ecc newEcl : vector<Ecc>{Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
+ if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
+ ecl = newEcl;
+ }
+
+ // Concatenate all segments to create the data bit string
+ BitBuffer bb;
+ for (const QrSegment &seg : segs) {
+ bb.appendBits(static_cast<uint32_t>(seg.getMode().getModeBits()), 4);
+ bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version));
+ bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
+ }
+ if (bb.size() != static_cast<unsigned int>(dataUsedBits))
+ throw std::logic_error("Assertion error");
+
+ // Add terminator and pad up to a byte if applicable
+ size_t dataCapacityBits = static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8;
+ if (bb.size() > dataCapacityBits)
+ throw std::logic_error("Assertion error");
+ bb.appendBits(0, std::min(4, static_cast<int>(dataCapacityBits - bb.size())));
+ bb.appendBits(0, (8 - static_cast<int>(bb.size() % 8)) % 8);
+ if (bb.size() % 8 != 0)
+ throw std::logic_error("Assertion error");
+
+ // Pad with alternating bytes until data capacity is reached
+ for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ bb.appendBits(padByte, 8);
+
+ // Pack bits into bytes in big endian
+ vector<uint8_t> dataCodewords(bb.size() / 8);
+ for (size_t i = 0; i < bb.size(); i++)
+ dataCodewords[i >> 3] |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
+
+ // Create the QR Code object
+ return QrCode(version, ecl, dataCodewords, mask);
+}
+
+
+QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk) :
+ // Initialize fields and check arguments
+ version(ver),
+ errorCorrectionLevel(ecl) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw std::domain_error("Version value out of range");
+ if (msk < -1 || msk > 7)
+ throw std::domain_error("Mask value out of range");
+ size = ver * 4 + 17;
+ size_t sz = static_cast<size_t>(size);
+ modules = vector<vector<bool> >(sz, vector<bool>(sz)); // Initially all white
+ isFunction = vector<vector<bool> >(sz, vector<bool>(sz));
+
+ // Compute ECC, draw modules
+ drawFunctionPatterns();
+ const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords);
+ drawCodewords(allCodewords);
+
+ // Do masking
+ if (msk == -1) { // Automatically choose best mask
+ long minPenalty = LONG_MAX;
+ for (int i = 0; i < 8; i++) {
+ applyMask(i);
+ drawFormatBits(i);
+ long penalty = getPenaltyScore();
+ if (penalty < minPenalty) {
+ msk = i;
+ minPenalty = penalty;
+ }
+ applyMask(i); // Undoes the mask due to XOR
+ }
+ }
+ if (msk < 0 || msk > 7)
+ throw std::logic_error("Assertion error");
+ this->mask = msk;
+ applyMask(msk); // Apply the final choice of mask
+ drawFormatBits(msk); // Overwrite old format bits
+
+ isFunction.clear();
+ isFunction.shrink_to_fit();
+}
+
+
+int QrCode::getVersion() const {
+ return version;
+}
+
+
+int QrCode::getSize() const {
+ return size;
+}
+
+
+QrCode::Ecc QrCode::getErrorCorrectionLevel() const {
+ return errorCorrectionLevel;
+}
+
+
+int QrCode::getMask() const {
+ return mask;
+}
+
+
+bool QrCode::getModule(int x, int y) const {
+ return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
+}
+
+
+std::string QrCode::toSvgString(int border) const {
+ if (border < 0)
+ throw std::domain_error("Border must be non-negative");
+ if (border > INT_MAX / 2 || border * 2 > INT_MAX - size)
+ throw std::overflow_error("Border too large");
+
+ std::ostringstream sb;
+ sb << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ sb << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
+ sb << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 ";
+ sb << (size + border * 2) << " " << (size + border * 2) << "\" stroke=\"none\">\n";
+ sb << "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n";
+ sb << "\t<path d=\"";
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++) {
+ if (getModule(x, y)) {
+ if (x != 0 || y != 0)
+ sb << " ";
+ sb << "M" << (x + border) << "," << (y + border) << "h1v1h-1z";
+ }
+ }
+ }
+ sb << "\" fill=\"#000000\"/>\n";
+ sb << "</svg>\n";
+ return sb.str();
+}
+
+
+void QrCode::drawFunctionPatterns() {
+ // Draw horizontal and vertical timing patterns
+ for (int i = 0; i < size; i++) {
+ setFunctionModule(6, i, i % 2 == 0);
+ setFunctionModule(i, 6, i % 2 == 0);
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ drawFinderPattern(3, 3);
+ drawFinderPattern(size - 4, 3);
+ drawFinderPattern(3, size - 4);
+
+ // Draw numerous alignment patterns
+ const vector<int> alignPatPos = getAlignmentPatternPositions();
+ size_t numAlign = alignPatPos.size();
+ for (size_t i = 0; i < numAlign; i++) {
+ for (size_t j = 0; j < numAlign; j++) {
+ // Don't draw on the three finder corners
+ if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
+ drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
+ }
+ }
+
+ // Draw configuration data
+ drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
+ drawVersion();
+}
+
+
+void QrCode::drawFormatBits(int msk) {
+ // Calculate error correction code and pack bits
+ int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3
+ int rem = data;
+ for (int i = 0; i < 10; i++)
+ rem = (rem << 1) ^ ((rem >> 9) * 0x537);
+ int bits = (data << 10 | rem) ^ 0x5412; // uint15
+ if (bits >> 15 != 0)
+ throw std::logic_error("Assertion error");
+
+ // Draw first copy
+ for (int i = 0; i <= 5; i++)
+ setFunctionModule(8, i, getBit(bits, i));
+ setFunctionModule(8, 7, getBit(bits, 6));
+ setFunctionModule(8, 8, getBit(bits, 7));
+ setFunctionModule(7, 8, getBit(bits, 8));
+ for (int i = 9; i < 15; i++)
+ setFunctionModule(14 - i, 8, getBit(bits, i));
+
+ // Draw second copy
+ for (int i = 0; i < 8; i++)
+ setFunctionModule(size - 1 - i, 8, getBit(bits, i));
+ for (int i = 8; i < 15; i++)
+ setFunctionModule(8, size - 15 + i, getBit(bits, i));
+ setFunctionModule(8, size - 8, true); // Always black
+}
+
+
+void QrCode::drawVersion() {
+ if (version < 7)
+ return;
+
+ // Calculate error correction code and pack bits
+ int rem = version; // version is uint6, in the range [7, 40]
+ for (int i = 0; i < 12; i++)
+ rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
+ long bits = static_cast<long>(version) << 12 | rem; // uint18
+ if (bits >> 18 != 0)
+ throw std::logic_error("Assertion error");
+
+ // Draw two copies
+ for (int i = 0; i < 18; i++) {
+ bool bit = getBit(bits, i);
+ int a = size - 11 + i % 3;
+ int b = i / 3;
+ setFunctionModule(a, b, bit);
+ setFunctionModule(b, a, bit);
+ }
+}
+
+
+void QrCode::drawFinderPattern(int x, int y) {
+ for (int dy = -4; dy <= 4; dy++) {
+ for (int dx = -4; dx <= 4; dx++) {
+ int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm
+ int xx = x + dx, yy = y + dy;
+ if (0 <= xx && xx < size && 0 <= yy && yy < size)
+ setFunctionModule(xx, yy, dist != 2 && dist != 4);
+ }
+ }
+}
+
+
+void QrCode::drawAlignmentPattern(int x, int y) {
+ for (int dy = -2; dy <= 2; dy++) {
+ for (int dx = -2; dx <= 2; dx++)
+ setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1);
+ }
+}
+
+
+void QrCode::setFunctionModule(int x, int y, bool isBlack) {
+ size_t ux = static_cast<size_t>(x);
+ size_t uy = static_cast<size_t>(y);
+ modules .at(uy).at(ux) = isBlack;
+ isFunction.at(uy).at(ux) = true;
+}
+
+
+bool QrCode::module(int x, int y) const {
+ return modules.at(static_cast<size_t>(y)).at(static_cast<size_t>(x));
+}
+
+
+vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
+ if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
+ throw std::invalid_argument("Invalid argument");
+
+ // Calculate parameter numbers
+ int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version];
+ int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast<int>(errorCorrectionLevel)][version];
+ int rawCodewords = getNumRawDataModules(version) / 8;
+ int numShortBlocks = numBlocks - rawCodewords % numBlocks;
+ int shortBlockLen = rawCodewords / numBlocks;
+
+ // Split data into blocks and append ECC to each block
+ vector<vector<uint8_t> > blocks;
+ const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
+ for (int i = 0, k = 0; i < numBlocks; i++) {
+ vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
+ k += static_cast<int>(dat.size());
+ const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
+ if (i < numShortBlocks)
+ dat.push_back(0);
+ dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
+ blocks.push_back(std::move(dat));
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ vector<uint8_t> result;
+ for (size_t i = 0; i < blocks.at(0).size(); i++) {
+ for (size_t j = 0; j < blocks.size(); j++) {
+ // Skip the padding byte in short blocks
+ if (i != static_cast<unsigned int>(shortBlockLen - blockEccLen) || j >= static_cast<unsigned int>(numShortBlocks))
+ result.push_back(blocks.at(j).at(i));
+ }
+ }
+ if (result.size() != static_cast<unsigned int>(rawCodewords))
+ throw std::logic_error("Assertion error");
+ return result;
+}
+
+
+void QrCode::drawCodewords(const vector<uint8_t> &data) {
+ if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
+ throw std::invalid_argument("Invalid argument");
+
+ size_t i = 0; // Bit index into the data
+ // Do the funny zigzag scan
+ for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
+ if (right == 6)
+ right = 5;
+ for (int vert = 0; vert < size; vert++) { // Vertical counter
+ for (int j = 0; j < 2; j++) {
+ size_t x = static_cast<size_t>(right - j); // Actual x coordinate
+ bool upward = ((right + 1) & 2) == 0;
+ size_t y = static_cast<size_t>(upward ? size - 1 - vert : vert); // Actual y coordinate
+ if (!isFunction.at(y).at(x) && i < data.size() * 8) {
+ modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast<int>(i & 7));
+ i++;
+ }
+ // If this QR Code has any remainder bits (0 to 7), they were assigned as
+ // 0/false/white by the constructor and are left unchanged by this method
+ }
+ }
+ }
+ if (i != data.size() * 8)
+ throw std::logic_error("Assertion error");
+}
+
+
+void QrCode::applyMask(int msk) {
+ if (msk < 0 || msk > 7)
+ throw std::domain_error("Mask value out of range");
+ size_t sz = static_cast<size_t>(size);
+ for (size_t y = 0; y < sz; y++) {
+ for (size_t x = 0; x < sz; x++) {
+ bool invert;
+ switch (msk) {
+ case 0: invert = (x + y) % 2 == 0; break;
+ case 1: invert = y % 2 == 0; break;
+ case 2: invert = x % 3 == 0; break;
+ case 3: invert = (x + y) % 3 == 0; break;
+ case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
+ case 5: invert = x * y % 2 + x * y % 3 == 0; break;
+ case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
+ case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
+ default: throw std::logic_error("Assertion error");
+ }
+ modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
+ }
+ }
+}
+
+
+long QrCode::getPenaltyScore() const {
+ long result = 0;
+
+ // Adjacent modules in row having same color, and finder-like patterns
+ for (int y = 0; y < size; y++) {
+ bool runColor = false;
+ int runX = 0;
+ std::array<int,7> runHistory = {};
+ for (int x = 0; x < size; x++) {
+ if (module(x, y) == runColor) {
+ runX++;
+ if (runX == 5)
+ result += PENALTY_N1;
+ else if (runX > 5)
+ result++;
+ } else {
+ finderPenaltyAddHistory(runX, runHistory);
+ if (!runColor)
+ result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
+ runColor = module(x, y);
+ runX = 1;
+ }
+ }
+ result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
+ }
+ // Adjacent modules in column having same color, and finder-like patterns
+ for (int x = 0; x < size; x++) {
+ bool runColor = false;
+ int runY = 0;
+ std::array<int,7> runHistory = {};
+ for (int y = 0; y < size; y++) {
+ if (module(x, y) == runColor) {
+ runY++;
+ if (runY == 5)
+ result += PENALTY_N1;
+ else if (runY > 5)
+ result++;
+ } else {
+ finderPenaltyAddHistory(runY, runHistory);
+ if (!runColor)
+ result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
+ runColor = module(x, y);
+ runY = 1;
+ }
+ }
+ result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
+ }
+
+ // 2*2 blocks of modules having same color
+ for (int y = 0; y < size - 1; y++) {
+ for (int x = 0; x < size - 1; x++) {
+ bool color = module(x, y);
+ if ( color == module(x + 1, y) &&
+ color == module(x, y + 1) &&
+ color == module(x + 1, y + 1))
+ result += PENALTY_N2;
+ }
+ }
+
+ // Balance of black and white modules
+ int black = 0;
+ for (const vector<bool> &row : modules) {
+ for (bool color : row) {
+ if (color)
+ black++;
+ }
+ }
+ int total = size * size; // Note that size is odd, so black/total != 1/2
+ // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)%
+ int k = static_cast<int>((std::abs(black * 20L - total * 10L) + total - 1) / total) - 1;
+ result += k * PENALTY_N4;
+ return result;
+}
+
+
+vector<int> QrCode::getAlignmentPatternPositions() const {
+ if (version == 1)
+ return vector<int>();
+ else {
+ int numAlign = version / 7 + 2;
+ int step = (version == 32) ? 26 :
+ (version*4 + numAlign*2 + 1) / (numAlign*2 - 2) * 2;
+ vector<int> result;
+ for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
+ result.insert(result.begin(), pos);
+ result.insert(result.begin(), 6);
+ return result;
+ }
+}
+
+
+int QrCode::getNumRawDataModules(int ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw std::domain_error("Version number out of range");
+ int result = (16 * ver + 128) * ver + 64;
+ if (ver >= 2) {
+ int numAlign = ver / 7 + 2;
+ result -= (25 * numAlign - 10) * numAlign - 55;
+ if (ver >= 7)
+ result -= 36;
+ }
+ if (!(208 <= result && result <= 29648))
+ throw std::logic_error("Assertion error");
+ return result;
+}
+
+
+int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
+ return getNumRawDataModules(ver) / 8
+ - ECC_CODEWORDS_PER_BLOCK [static_cast<int>(ecl)][ver]
+ * NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(ecl)][ver];
+}
+
+
+vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
+ if (degree < 1 || degree > 255)
+ throw std::domain_error("Degree out of range");
+ // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
+ // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
+ vector<uint8_t> result(static_cast<size_t>(degree));
+ result.at(result.size() - 1) = 1; // Start off with the monomial x^0
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // and drop the highest monomial term which is always 1x^degree.
+ // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ uint8_t root = 1;
+ for (int i = 0; i < degree; i++) {
+ // Multiply the current product by (x - r^i)
+ for (size_t j = 0; j < result.size(); j++) {
+ result.at(j) = reedSolomonMultiply(result.at(j), root);
+ if (j + 1 < result.size())
+ result.at(j) ^= result.at(j + 1);
+ }
+ root = reedSolomonMultiply(root, 0x02);
+ }
+ return result;
+}
+
+
+vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) {
+ vector<uint8_t> result(divisor.size());
+ for (uint8_t b : data) { // Polynomial division
+ uint8_t factor = b ^ result.at(0);
+ result.erase(result.begin());
+ result.push_back(0);
+ for (size_t i = 0; i < result.size(); i++)
+ result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
+ }
+ return result;
+}
+
+
+uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
+ // Russian peasant multiplication
+ int z = 0;
+ for (int i = 7; i >= 0; i--) {
+ z = (z << 1) ^ ((z >> 7) * 0x11D);
+ z ^= ((y >> i) & 1) * x;
+ }
+ if (z >> 8 != 0)
+ throw std::logic_error("Assertion error");
+ return static_cast<uint8_t>(z);
+}
+
+
+int QrCode::finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const {
+ int n = runHistory.at(1);
+ if (n > size * 3)
+ throw std::logic_error("Assertion error");
+ bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n;
+ return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0)
+ + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0);
+}
+
+
+int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const {
+ if (currentRunColor) { // Terminate black run
+ finderPenaltyAddHistory(currentRunLength, runHistory);
+ currentRunLength = 0;
+ }
+ currentRunLength += size; // Add white border to final run
+ finderPenaltyAddHistory(currentRunLength, runHistory);
+ return finderPenaltyCountPatterns(runHistory);
+}
+
+
+void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const {
+ if (runHistory.at(0) == 0)
+ currentRunLength += size; // Add white border to initial run
+ std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
+ runHistory.at(0) = currentRunLength;
+}
+
+
+bool QrCode::getBit(long x, int i) {
+ return ((x >> i) & 1) != 0;
+}
+
+
+/*---- Tables of constants ----*/
+
+const int QrCode::PENALTY_N1 = 3;
+const int QrCode::PENALTY_N2 = 3;
+const int QrCode::PENALTY_N3 = 40;
+const int QrCode::PENALTY_N4 = 10;
+
+
+const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
+ {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
+ {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
+ {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
+};
+
+const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
+ {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
+ {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
+ {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
+};
+
+
+data_too_long::data_too_long(const std::string &msg) :
+ std::length_error(msg) {}
+
+
+
+BitBuffer::BitBuffer()
+ : std::vector<bool>() {}
+
+
+void BitBuffer::appendBits(std::uint32_t val, int len) {
+ if (len < 0 || len > 31 || val >> len != 0)
+ throw std::domain_error("Value out of range");
+ for (int i = len - 1; i >= 0; i--) // Append bit by bit
+ this->push_back(((val >> i) & 1) != 0);
+}
+
+}
diff --git a/external/qrcodegen/QrCode.hpp b/external/qrcodegen/QrCode.hpp
new file mode 100644
index 000000000..7341e4102
--- /dev/null
+++ b/external/qrcodegen/QrCode.hpp
@@ -0,0 +1,556 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * Copyright (c) Project Nayuki. (MIT License)
+ * https://www.nayuki.io/page/qr-code-generator-library
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * - The Software is provided "as is", without warranty of any kind, express or
+ * implied, including but not limited to the warranties of merchantability,
+ * fitness for a particular purpose and noninfringement. In no event shall the
+ * authors or copyright holders be liable for any claim, damages or other
+ * liability, whether in an action of contract, tort or otherwise, arising from,
+ * out of or in connection with the Software or the use or other dealings in the
+ * Software.
+ */
+
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+
+namespace qrcodegen {
+
+/*
+ * A segment of character/binary/control data in a QR Code symbol.
+ * Instances of this class are immutable.
+ * The mid-level way to create a segment is to take the payload data
+ * and call a static factory function such as QrSegment::makeNumeric().
+ * The low-level way to create a segment is to custom-make the bit buffer
+ * and call the QrSegment() constructor with appropriate values.
+ * This segment class imposes no length restrictions, but QR Codes have restrictions.
+ * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
+ * Any segment longer than this is meaningless for the purpose of generating QR Codes.
+ */
+class QrSegment final {
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * Describes how a segment's data bits are interpreted. Immutable.
+ */
+ public: class Mode final {
+
+ /*-- Constants --*/
+
+ public: static const Mode NUMERIC;
+ public: static const Mode ALPHANUMERIC;
+ public: static const Mode BYTE;
+ public: static const Mode KANJI;
+ public: static const Mode ECI;
+
+
+ /*-- Fields --*/
+
+ // The mode indicator bits, which is a uint4 value (range 0 to 15).
+ private: int modeBits;
+
+ // Number of character count bits for three different version ranges.
+ private: int numBitsCharCount[3];
+
+
+ /*-- Constructor --*/
+
+ private: Mode(int mode, int cc0, int cc1, int cc2);
+
+
+ /*-- Methods --*/
+
+ /*
+ * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15).
+ */
+ public: int getModeBits() const;
+
+ /*
+ * (Package-private) Returns the bit width of the character count field for a segment in
+ * this mode in a QR Code at the given version number. The result is in the range [0, 16].
+ */
+ public: int numCharCountBits(int ver) const;
+
+ };
+
+
+
+ /*---- Static factory functions (mid level) ----*/
+
+ /*
+ * Returns a segment representing the given binary data encoded in
+ * byte mode. All input byte vectors are acceptable. Any text string
+ * can be converted to UTF-8 bytes and encoded as a byte mode segment.
+ */
+ public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data);
+
+
+ /*
+ * Returns a segment representing the given string of decimal digits encoded in numeric mode.
+ */
+ public: static QrSegment makeNumeric(const char *digits);
+
+
+ /*
+ * Returns a segment representing the given text string encoded in alphanumeric mode.
+ * The characters allowed are: 0 to 9, A to Z (uppercase only), space,
+ * dollar, percent, asterisk, plus, hyphen, period, slash, colon.
+ */
+ public: static QrSegment makeAlphanumeric(const char *text);
+
+
+ /*
+ * Returns a list of zero or more segments to represent the given text string. The result
+ * may use various segment modes and switch modes to optimize the length of the bit stream.
+ */
+ public: static std::vector<QrSegment> makeSegments(const char *text);
+
+
+ /*
+ * Returns a segment representing an Extended Channel Interpretation
+ * (ECI) designator with the given assignment value.
+ */
+ public: static QrSegment makeEci(long assignVal);
+
+
+ /*---- Public static helper functions ----*/
+
+ /*
+ * Tests whether the given string can be encoded as a segment in alphanumeric mode.
+ * A string is encodable iff each character is in the following set: 0 to 9, A to Z
+ * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
+ */
+ public: static bool isAlphanumeric(const char *text);
+
+
+ /*
+ * Tests whether the given string can be encoded as a segment in numeric mode.
+ * A string is encodable iff each character is in the range 0 to 9.
+ */
+ public: static bool isNumeric(const char *text);
+
+
+
+ /*---- Instance fields ----*/
+
+ /* The mode indicator of this segment. Accessed through getMode(). */
+ private: Mode mode;
+
+ /* The length of this segment's unencoded data. Measured in characters for
+ * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
+ * Always zero or positive. Not the same as the data's bit length.
+ * Accessed through getNumChars(). */
+ private: int numChars;
+
+ /* The data bits of this segment. Accessed through getData(). */
+ private: std::vector<bool> data;
+
+
+ /*---- Constructors (low level) ----*/
+
+ /*
+ * Creates a new QR Code segment with the given attributes and data.
+ * The character count (numCh) must agree with the mode and the bit buffer length,
+ * but the constraint isn't checked. The given bit buffer is copied and stored.
+ */
+ public: QrSegment(Mode md, int numCh, const std::vector<bool> &dt);
+
+
+ /*
+ * Creates a new QR Code segment with the given parameters and data.
+ * The character count (numCh) must agree with the mode and the bit buffer length,
+ * but the constraint isn't checked. The given bit buffer is moved and stored.
+ */
+ public: QrSegment(Mode md, int numCh, std::vector<bool> &&dt);
+
+
+ /*---- Methods ----*/
+
+ /*
+ * Returns the mode field of this segment.
+ */
+ public: Mode getMode() const;
+
+
+ /*
+ * Returns the character count field of this segment.
+ */
+ public: int getNumChars() const;
+
+
+ /*
+ * Returns the data bits of this segment.
+ */
+ public: const std::vector<bool> &getData() const;
+
+
+ // (Package-private) Calculates the number of bits needed to encode the given segments at
+ // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a
+ // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX.
+ public: static int getTotalBits(const std::vector<QrSegment> &segs, int version);
+
+
+ /*---- Private constant ----*/
+
+ /* The set of all legal characters in alphanumeric mode, where
+ * each character value maps to the index in the string. */
+ private: static const char *ALPHANUMERIC_CHARSET;
+
+};
+
+
+
+/*
+ * A QR Code symbol, which is a type of two-dimension barcode.
+ * Invented by Denso Wave and described in the ISO/IEC 18004 standard.
+ * Instances of this class represent an immutable square grid of black and white cells.
+ * The class provides static factory functions to create a QR Code from text or binary data.
+ * The class covers the QR Code Model 2 specification, supporting all versions (sizes)
+ * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
+ *
+ * Ways to create a QR Code object:
+ * - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary().
+ * - Mid level: Custom-make the list of segments and call QrCode::encodeSegments().
+ * - Low level: Custom-make the array of data codeword bytes (including
+ * segment headers and final padding, excluding error correction codewords),
+ * supply the appropriate version number, and call the QrCode() constructor.
+ * (Note that all ways require supplying the desired error correction level.)
+ */
+class QrCode final {
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * The error correction level in a QR Code symbol.
+ */
+ public: enum class Ecc {
+ LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords
+ MEDIUM , // The QR Code can tolerate about 15% erroneous codewords
+ QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
+ HIGH , // The QR Code can tolerate about 30% erroneous codewords
+ };
+
+
+ // Returns a value in the range 0 to 3 (unsigned 2-bit integer).
+ private: static int getFormatBits(Ecc ecl);
+
+
+
+ /*---- Static factory functions (high level) ----*/
+
+ /*
+ * Returns a QR Code representing the given Unicode text string at the given error correction level.
+ * As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer
+ * UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible
+ * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
+ * the ecl argument if it can be done without increasing the version.
+ */
+ public: static QrCode encodeText(const char *text, Ecc ecl);
+
+
+ /*
+ * Returns a QR Code representing the given binary data at the given error correction level.
+ * This function always encodes using the binary segment mode, not any text mode. The maximum number of
+ * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+ * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
+ */
+ public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl);
+
+
+ /*---- Static factory functions (mid level) ----*/
+
+ /*
+ * Returns a QR Code representing the given segments with the given encoding parameters.
+ * The smallest possible QR Code version within the given range is automatically
+ * chosen for the output. Iff boostEcl is true, then the ECC level of the result
+ * may be higher than the ecl argument if it can be done without increasing the
+ * version. The mask number is either between 0 to 7 (inclusive) to force that
+ * mask, or -1 to automatically choose an appropriate mask (which may be slow).
+ * This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and byte) to encode text in less space.
+ * This is a mid-level API; the high-level API is encodeText() and encodeBinary().
+ */
+ public: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
+ int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
+
+
+
+ /*---- Instance fields ----*/
+
+ // Immutable scalar parameters:
+
+ /* The version number of this QR Code, which is between 1 and 40 (inclusive).
+ * This determines the size of this barcode. */
+ private: int version;
+
+ /* The width and height of this QR Code, measured in modules, between
+ * 21 and 177 (inclusive). This is equal to version * 4 + 17. */
+ private: int size;
+
+ /* The error correction level used in this QR Code. */
+ private: Ecc errorCorrectionLevel;
+
+ /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
+ * Even if a QR Code is created with automatic masking requested (mask = -1),
+ * the resulting object still has a mask value between 0 and 7. */
+ private: int mask;
+
+ // Private grids of modules/pixels, with dimensions of size*size:
+
+ // The modules of this QR Code (false = white, true = black).
+ // Immutable after constructor finishes. Accessed through getModule().
+ private: std::vector<std::vector<bool> > modules;
+
+ // Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
+ private: std::vector<std::vector<bool> > isFunction;
+
+
+
+ /*---- Constructor (low level) ----*/
+
+ /*
+ * Creates a new QR Code with the given version number,
+ * error correction level, data codeword bytes, and mask number.
+ * This is a low-level API that most users should not use directly.
+ * A mid-level API is the encodeSegments() function.
+ */
+ public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk);
+
+
+
+ /*---- Public instance methods ----*/
+
+ /*
+ * Returns this QR Code's version, in the range [1, 40].
+ */
+ public: int getVersion() const;
+
+
+ /*
+ * Returns this QR Code's size, in the range [21, 177].
+ */
+ public: int getSize() const;
+
+
+ /*
+ * Returns this QR Code's error correction level.
+ */
+ public: Ecc getErrorCorrectionLevel() const;
+
+
+ /*
+ * Returns this QR Code's mask, in the range [0, 7].
+ */
+ public: int getMask() const;
+
+
+ /*
+ * Returns the color of the module (pixel) at the given coordinates, which is false
+ * for white or true for black. The top left corner has the coordinates (x=0, y=0).
+ * If the given coordinates are out of bounds, then false (white) is returned.
+ */
+ public: bool getModule(int x, int y) const;
+
+
+ /*
+ * Returns a string of SVG code for an image depicting this QR Code, with the given number
+ * of border modules. The string always uses Unix newlines (\n), regardless of the platform.
+ */
+ public: std::string toSvgString(int border) const;
+
+
+
+ /*---- Private helper methods for constructor: Drawing function modules ----*/
+
+ // Reads this object's version field, and draws and marks all function modules.
+ private: void drawFunctionPatterns();
+
+
+ // Draws two copies of the format bits (with its own error correction code)
+ // based on the given mask and this object's error correction level field.
+ private: void drawFormatBits(int msk);
+
+
+ // Draws two copies of the version bits (with its own error correction code),
+ // based on this object's version field, iff 7 <= version <= 40.
+ private: void drawVersion();
+
+
+ // Draws a 9*9 finder pattern including the border separator,
+ // with the center module at (x, y). Modules can be out of bounds.
+ private: void drawFinderPattern(int x, int y);
+
+
+ // Draws a 5*5 alignment pattern, with the center module
+ // at (x, y). All modules must be in bounds.
+ private: void drawAlignmentPattern(int x, int y);
+
+
+ // Sets the color of a module and marks it as a function module.
+ // Only used by the constructor. Coordinates must be in bounds.
+ private: void setFunctionModule(int x, int y, bool isBlack);
+
+
+ // Returns the color of the module at the given coordinates, which must be in range.
+ private: bool module(int x, int y) const;
+
+
+ /*---- Private helper methods for constructor: Codewords and masking ----*/
+
+ // Returns a new byte string representing the given data with the appropriate error correction
+ // codewords appended to it, based on this object's version and error correction level.
+ private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const;
+
+
+ // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+ // data area of this QR Code. Function modules need to be marked off before this is called.
+ private: void drawCodewords(const std::vector<std::uint8_t> &data);
+
+
+ // XORs the codeword modules in this QR Code with the given mask pattern.
+ // The function modules must be marked and the codeword bits must be drawn
+ // before masking. Due to the arithmetic of XOR, calling applyMask() with
+ // the same mask value a second time will undo the mask. A final well-formed
+ // QR Code needs exactly one (not zero, two, etc.) mask applied.
+ private: void applyMask(int msk);
+
+
+ // Calculates and returns the penalty score based on state of this QR Code's current modules.
+ // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
+ private: long getPenaltyScore() const;
+
+
+
+ /*---- Private helper functions ----*/
+
+ // Returns an ascending list of positions of alignment patterns for this version number.
+ // Each position is in the range [0,177), and are used on both the x and y axes.
+ // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
+ private: std::vector<int> getAlignmentPatternPositions() const;
+
+
+ // Returns the number of data bits that can be stored in a QR Code of the given version number, after
+ // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
+ // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
+ private: static int getNumRawDataModules(int ver);
+
+
+ // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
+ // QR Code of the given version number and error correction level, with remainder bits discarded.
+ // This stateless pure function could be implemented as a (40*4)-cell lookup table.
+ private: static int getNumDataCodewords(int ver, Ecc ecl);
+
+
+ // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
+ // implemented as a lookup table over all possible parameter values, instead of as an algorithm.
+ private: static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree);
+
+
+ // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
+ private: static std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor);
+
+
+ // Returns the product of the two given field elements modulo GF(2^8/0x11D).
+ // All inputs are valid. This could be implemented as a 256*256 lookup table.
+ private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y);
+
+
+ // Can only be called immediately after a white run is added, and
+ // returns either 0, 1, or 2. A helper function for getPenaltyScore().
+ private: int finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const;
+
+
+ // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
+ private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const;
+
+
+ // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
+ private: void finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const;
+
+
+ // Returns true iff the i'th bit of x is set to 1.
+ private: static bool getBit(long x, int i);
+
+
+ /*---- Constants and tables ----*/
+
+ // The minimum version number supported in the QR Code Model 2 standard.
+ public: static constexpr int MIN_VERSION = 1;
+
+ // The maximum version number supported in the QR Code Model 2 standard.
+ public: static constexpr int MAX_VERSION = 40;
+
+
+ // For use in getPenaltyScore(), when evaluating which mask is best.
+ private: static const int PENALTY_N1;
+ private: static const int PENALTY_N2;
+ private: static const int PENALTY_N3;
+ private: static const int PENALTY_N4;
+
+
+ private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
+ private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
+
+};
+
+
+
+/*---- Public exception class ----*/
+
+/*
+ * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include:
+ * - Decrease the error correction level if it was greater than Ecc::LOW.
+ * - If the encodeSegments() function was called with a maxVersion argument, then increase
+ * it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other
+ * factory functions because they search all versions up to QrCode::MAX_VERSION.)
+ * - Split the text data into better or optimal segments in order to reduce the number of bits required.
+ * - Change the text or binary data to be shorter.
+ * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).
+ * - Propagate the error upward to the caller/user.
+ */
+class data_too_long : public std::length_error {
+
+ public: explicit data_too_long(const std::string &msg);
+
+};
+
+
+
+/*
+ * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment.
+ */
+class BitBuffer final : public std::vector<bool> {
+
+ /*---- Constructor ----*/
+
+ // Creates an empty bit buffer (length 0).
+ public: BitBuffer();
+
+
+
+ /*---- Method ----*/
+
+ // Appends the given number of low-order bits of the given value
+ // to this buffer. Requires 0 <= len <= 31 and val < 2^len.
+ public: void appendBits(std::uint32_t val, int len);
+
+};
+
+}
diff --git a/external/supercop b/external/supercop
new file mode 160000
+Subproject 7d8b6878260061da56ade6d23dc833288659d0a
diff --git a/include/INode.h b/include/INode.h
index 0d896ca69..8ad8d03a1 100644
--- a/include/INode.h
+++ b/include/INode.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/include/IWallet.h b/include/IWallet.h
index 98362895d..74260ce35 100644
--- a/include/IWallet.h
+++ b/include/IWallet.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/snap b/snap
deleted file mode 120000
index ef5bb2b3c..000000000
--- a/snap
+++ /dev/null
@@ -1 +0,0 @@
-contrib/snap \ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d45363e24..07d4d58c3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/blockchain_db/CMakeLists.txt b/src/blockchain_db/CMakeLists.txt
index 0a21e4920..77faade17 100644
--- a/src/blockchain_db/CMakeLists.txt
+++ b/src/blockchain_db/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 01faf43c4..5c8dece2a 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -63,6 +63,7 @@ bool matches_category(relay_method method, relay_category category) noexcept
{
default:
case relay_method::local:
+ case relay_method::forward:
case relay_method::stem:
return false;
case relay_method::block:
@@ -79,6 +80,7 @@ void txpool_tx_meta_t::set_relay_method(relay_method method) noexcept
kept_by_block = 0;
do_not_relay = 0;
is_local = 0;
+ is_forwarding = 0;
dandelionpp_stem = 0;
switch (method)
@@ -89,8 +91,8 @@ void txpool_tx_meta_t::set_relay_method(relay_method method) noexcept
case relay_method::local:
is_local = 1;
break;
- default:
- case relay_method::fluff:
+ case relay_method::forward:
+ is_forwarding = 1;
break;
case relay_method::stem:
dandelionpp_stem = 1;
@@ -98,26 +100,45 @@ void txpool_tx_meta_t::set_relay_method(relay_method method) noexcept
case relay_method::block:
kept_by_block = 1;
break;
+ default:
+ case relay_method::fluff:
+ break;
}
}
relay_method txpool_tx_meta_t::get_relay_method() const noexcept
{
- if (kept_by_block)
- return relay_method::block;
- if (do_not_relay)
- return relay_method::none;
- if (is_local)
- return relay_method::local;
- if (dandelionpp_stem)
- return relay_method::stem;
+ const uint8_t state =
+ uint8_t(kept_by_block) +
+ (uint8_t(do_not_relay) << 1) +
+ (uint8_t(is_local) << 2) +
+ (uint8_t(is_forwarding) << 3) +
+ (uint8_t(dandelionpp_stem) << 4);
+
+ switch (state)
+ {
+ default: // error case
+ case 0:
+ break;
+ case 1:
+ return relay_method::block;
+ case 2:
+ return relay_method::none;
+ case 4:
+ return relay_method::local;
+ case 8:
+ return relay_method::forward;
+ case 16:
+ return relay_method::stem;
+ };
return relay_method::fluff;
}
bool txpool_tx_meta_t::upgrade_relay_method(relay_method method) noexcept
{
static_assert(relay_method::none < relay_method::local, "bad relay_method value");
- static_assert(relay_method::local < relay_method::stem, "bad relay_method value");
+ static_assert(relay_method::local < relay_method::forward, "bad relay_method value");
+ static_assert(relay_method::forward < relay_method::stem, "bad relay_method value");
static_assert(relay_method::stem < relay_method::fluff, "bad relay_method value");
static_assert(relay_method::fluff < relay_method::block, "bad relay_method value");
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 3e2387da4..9a321437b 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -160,7 +160,7 @@ struct txpool_tx_meta_t
uint64_t max_used_block_height;
uint64_t last_failed_height;
uint64_t receive_time;
- uint64_t last_relayed_time; //!< If Dandelion++ stem, randomized embargo timestamp. Otherwise, last relayed timestmap.
+ uint64_t last_relayed_time; //!< If received over i2p/tor, randomized forward time. If Dandelion++stem, randomized embargo time. Otherwise, last relayed timestamp
// 112 bytes
uint8_t kept_by_block;
uint8_t relayed;
@@ -169,7 +169,8 @@ struct txpool_tx_meta_t
uint8_t pruned: 1;
uint8_t is_local: 1;
uint8_t dandelionpp_stem : 1;
- uint8_t bf_padding: 4;
+ uint8_t is_forwarding: 1;
+ uint8_t bf_padding: 3;
uint8_t padding[76]; // till 192 bytes
@@ -1039,6 +1040,16 @@ public:
virtual difficulty_type get_block_difficulty(const uint64_t& height) const = 0;
/**
+ * @brief correct blocks cumulative difficulties that were incorrectly calculated due to the 'difficulty drift' bug
+ *
+ * If the block does not exist, the subclass should throw BLOCK_DNE
+ *
+ * @param start_height the height where the drift starts
+ * @param new_cumulative_difficulties new cumulative difficulties to be stored
+ */
+ virtual void correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties) = 0;
+
+ /**
* @brief fetch a block's already generated coins
*
* The subclass should return the total coins generated as of the block
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 5cec8879d..6ea55d09d 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
@@ -25,6 +25,13 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef _WIN32
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#endif
+
#include "db_lmdb.h"
#include <boost/filesystem.hpp>
@@ -1287,6 +1294,26 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
m_hardfork = nullptr;
}
+void BlockchainLMDB::check_mmap_support()
+{
+#ifndef _WIN32
+ const boost::filesystem::path mmap_test_file = m_folder / boost::filesystem::unique_path();
+ int mmap_test_fd = ::open(mmap_test_file.string().c_str(), O_RDWR | O_CREAT, 0600);
+ if (mmap_test_fd < 0)
+ throw0(DB_ERROR((std::string("Failed to check for mmap support: open failed: ") + strerror(errno)).c_str()));
+ epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([mmap_test_fd, &mmap_test_file]() {
+ ::close(mmap_test_fd);
+ boost::filesystem::remove(mmap_test_file.string());
+ });
+ if (write(mmap_test_fd, "mmaptest", 8) != 8)
+ throw0(DB_ERROR((std::string("Failed to check for mmap support: write failed: ") + strerror(errno)).c_str()));
+ void *mmap_res = mmap(NULL, 8, PROT_READ, MAP_SHARED, mmap_test_fd, 0);
+ if (mmap_res == MAP_FAILED)
+ throw0(DB_ERROR("This filesystem does not support mmap: use --data-dir to place the blockchain on a filesystem which does"));
+ munmap(mmap_res, 8);
+#endif
+}
+
void BlockchainLMDB::open(const std::string& filename, const int db_flags)
{
int result;
@@ -1328,6 +1355,8 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
m_folder = filename;
+ check_mmap_support();
+
#ifdef __OpenBSD__
if ((mdb_flags & MDB_WRITEMAP) == 0) {
MCLOG_RED(el::Level::Info, "global", "Running on OpenBSD: forcing WRITEMAP");
@@ -2750,6 +2779,44 @@ difficulty_type BlockchainLMDB::get_block_difficulty(const uint64_t& height) con
return diff1 - diff2;
}
+void BlockchainLMDB::correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
+
+ int result = 0;
+ block_wtxn_start();
+ CURSOR(block_info)
+
+ const uint64_t bc_height = height();
+ if (start_height + new_cumulative_difficulties.size() != bc_height)
+ {
+ block_wtxn_abort();
+ throw0(DB_ERROR("Incorrect new_cumulative_difficulties size"));
+ }
+
+ for (uint64_t height = start_height; height < bc_height; ++height)
+ {
+ MDB_val_set(key, height);
+ result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &key, MDB_GET_BOTH);
+ if (result)
+ throw1(BLOCK_DNE(lmdb_error("Failed to get block info: ", result).c_str()));
+
+ mdb_block_info bi = *(mdb_block_info*)key.mv_data;
+ const difficulty_type d = new_cumulative_difficulties[height - start_height];
+ bi.bi_diff_hi = ((d >> 64) & 0xffffffffffffffff).convert_to<uint64_t>();
+ bi.bi_diff_lo = (d & 0xffffffffffffffff).convert_to<uint64_t>();
+
+ MDB_val_set(key2, height);
+ MDB_val_set(val, bi);
+ result = mdb_cursor_put(m_cur_block_info, &key2, &val, MDB_CURRENT);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to overwrite block info to db transaction: ", result).c_str()));
+ }
+ block_wtxn_stop();
+}
+
uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& height) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -4048,7 +4115,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial) const
{
if (amounts.size() != 1 && amounts.size() != offsets.size())
- throw0(DB_ERROR("Invalid sizes of amounts and offets"));
+ throw0(DB_ERROR("Invalid sizes of amounts and offsets"));
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
TIME_MEASURE_START(db3);
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 6ddeed671..5abb8014f 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
@@ -229,6 +229,8 @@ public:
virtual difficulty_type get_block_difficulty(const uint64_t& height) const;
+ virtual void correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties);
+
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const;
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const;
@@ -356,6 +358,7 @@ public:
static int compare_string(const MDB_val *a, const MDB_val *b);
private:
+ void check_mmap_support();
void do_resize(uint64_t size_increase=0);
bool need_resize(uint64_t threshold_size=0) const;
diff --git a/src/blockchain_db/locked_txn.h b/src/blockchain_db/locked_txn.h
index d14631ddb..1834f56fb 100644
--- a/src/blockchain_db/locked_txn.h
+++ b/src/blockchain_db/locked_txn.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 638dd3b37..92911d081 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -69,8 +69,8 @@ public:
virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const override { return cryptonote::blobdata(); }
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
- virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const { return false; }
- virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const { return false; }
+ virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const override { return false; }
+ virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const override { return false; }
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const override { return false; }
virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; }
@@ -82,6 +82,7 @@ public:
virtual std::vector<uint64_t> get_block_weights(uint64_t start_height, size_t count) const override { return {}; }
virtual cryptonote::difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const override { return 10; }
virtual cryptonote::difficulty_type get_block_difficulty(const uint64_t& height) const override { return 0; }
+ virtual void correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties) override {}
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const override { return 10000000000; }
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const override { return 128; }
virtual std::vector<uint64_t> get_long_term_block_weights(uint64_t start_height, size_t count) const override { return {}; }
diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt
index 0ba7ee86c..ac533596a 100644
--- a/src/blockchain_utilities/CMakeLists.txt
+++ b/src/blockchain_utilities/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/blockchain_utilities/README.md b/src/blockchain_utilities/README.md
index 1462e3186..4a233bcf5 100644
--- a/src/blockchain_utilities/README.md
+++ b/src/blockchain_utilities/README.md
@@ -1,6 +1,6 @@
# Monero Blockchain Utilities
-Copyright (c) 2014-2019, The Monero Project
+Copyright (c) 2014-2020, The Monero Project
## Introduction
diff --git a/src/blockchain_utilities/blockchain_ancestry.cpp b/src/blockchain_utilities/blockchain_ancestry.cpp
index db6d6f7d7..89b932e4f 100644
--- a/src/blockchain_utilities/blockchain_ancestry.cpp
+++ b/src/blockchain_utilities/blockchain_ancestry.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp
index 4a5712921..a847f6a9d 100644
--- a/src/blockchain_utilities/blockchain_blackball.cpp
+++ b/src/blockchain_utilities/blockchain_blackball.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_depth.cpp b/src/blockchain_utilities/blockchain_depth.cpp
index 153f5f7c6..6199586bf 100644
--- a/src/blockchain_utilities/blockchain_depth.cpp
+++ b/src/blockchain_utilities/blockchain_depth.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp
index b180f88de..e55930b00 100644
--- a/src/blockchain_utilities/blockchain_export.cpp
+++ b/src/blockchain_utilities/blockchain_export.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 852e9cf4f..ab2313096 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp b/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp
index cee24d4da..f8763710e 100644
--- a/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp
+++ b/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_stats.cpp b/src/blockchain_utilities/blockchain_stats.cpp
index 0d18b8819..c9c815f2a 100644
--- a/src/blockchain_utilities/blockchain_stats.cpp
+++ b/src/blockchain_utilities/blockchain_stats.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_usage.cpp b/src/blockchain_utilities/blockchain_usage.cpp
index 2fa56452b..6e87a0974 100644
--- a/src/blockchain_utilities/blockchain_usage.cpp
+++ b/src/blockchain_utilities/blockchain_usage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blockchain_utilities.h b/src/blockchain_utilities/blockchain_utilities.h
index e8615cf86..035e2397f 100644
--- a/src/blockchain_utilities/blockchain_utilities.h
+++ b/src/blockchain_utilities/blockchain_utilities.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blocksdat_file.cpp b/src/blockchain_utilities/blocksdat_file.cpp
index df3c6cafc..b9ef1de7d 100644
--- a/src/blockchain_utilities/blocksdat_file.cpp
+++ b/src/blockchain_utilities/blocksdat_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/blocksdat_file.h b/src/blockchain_utilities/blocksdat_file.h
index 72b7afc17..567505ac1 100644
--- a/src/blockchain_utilities/blocksdat_file.h
+++ b/src/blockchain_utilities/blocksdat_file.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -43,7 +43,6 @@
#include <algorithm>
#include <cstdio>
#include <fstream>
-#include <boost/iostreams/copy.hpp>
#include <atomic>
#include "common/command_line.h"
diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp
index 252c79776..a4704626f 100644
--- a/src/blockchain_utilities/bootstrap_file.cpp
+++ b/src/blockchain_utilities/bootstrap_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blockchain_utilities/bootstrap_file.h b/src/blockchain_utilities/bootstrap_file.h
index 1e6ef5d81..23dbb64d7 100644
--- a/src/blockchain_utilities/bootstrap_file.h
+++ b/src/blockchain_utilities/bootstrap_file.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -41,7 +41,6 @@
#include <algorithm>
#include <cstdio>
#include <fstream>
-#include <boost/iostreams/copy.hpp>
#include <atomic>
#include "common/command_line.h"
diff --git a/src/blockchain_utilities/bootstrap_serialization.h b/src/blockchain_utilities/bootstrap_serialization.h
index 70b3eea7e..bcc8c7e15 100644
--- a/src/blockchain_utilities/bootstrap_serialization.h
+++ b/src/blockchain_utilities/bootstrap_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/blocks/CMakeLists.txt b/src/blocks/CMakeLists.txt
index 0b7b02fee..051c60886 100644
--- a/src/blocks/CMakeLists.txt
+++ b/src/blocks/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat
index b14f9e8d2..fa58387ab 100644
--- a/src/blocks/checkpoints.dat
+++ b/src/blocks/checkpoints.dat
Binary files differ
diff --git a/src/checkpoints/CMakeLists.txt b/src/checkpoints/CMakeLists.txt
index d324f518e..46d6fedf1 100644
--- a/src/checkpoints/CMakeLists.txt
+++ b/src/checkpoints/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp
index 4a4b3c5c2..6e7e1acba 100644
--- a/src/checkpoints/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,6 +34,7 @@
#include "string_tools.h"
#include "storages/portable_storage_template_helper.h" // epee json include
#include "serialization/keyvalue_serialization.h"
+#include <functional>
#include <vector>
using namespace epee;
@@ -71,7 +72,7 @@ namespace cryptonote
{
}
//---------------------------------------------------------------------------
- bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
+ bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str, const std::string& difficulty_str)
{
crypto::hash h = crypto::null_hash;
bool r = epee::string_tools::hex_to_pod(hash_str, h);
@@ -83,6 +84,23 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(h == m_points[height], false, "Checkpoint at given height already exists, and hash for new checkpoint was different!");
}
m_points[height] = h;
+ if (!difficulty_str.empty())
+ {
+ try
+ {
+ difficulty_type difficulty(difficulty_str);
+ if (m_difficulty_points.count(height))
+ {
+ CHECK_AND_ASSERT_MES(difficulty == m_difficulty_points[height], false, "Difficulty checkpoint at given height already exists, and difficulty for new checkpoint was different!");
+ }
+ m_difficulty_points[height] = difficulty;
+ }
+ catch (...)
+ {
+ LOG_ERROR("Failed to parse difficulty checkpoint: " << difficulty_str);
+ return false;
+ }
+ }
return true;
}
//---------------------------------------------------------------------------
@@ -133,17 +151,20 @@ namespace cryptonote
//---------------------------------------------------------------------------
uint64_t checkpoints::get_max_height() const
{
- std::map< uint64_t, crypto::hash >::const_iterator highest =
- std::max_element( m_points.begin(), m_points.end(),
- ( boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _1) <
- boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _2 ) ) );
- return highest->first;
+ if (m_points.empty())
+ return 0;
+ return m_points.rbegin()->first;
}
//---------------------------------------------------------------------------
const std::map<uint64_t, crypto::hash>& checkpoints::get_points() const
{
return m_points;
}
+ //---------------------------------------------------------------------------
+ const std::map<uint64_t, difficulty_type>& checkpoints::get_difficulty_points() const
+ {
+ return m_difficulty_points;
+ }
bool checkpoints::check_for_conflicts(const checkpoints& other) const
{
@@ -161,56 +182,60 @@ namespace cryptonote
{
if (nettype == TESTNET)
{
- ADD_CHECKPOINT(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b");
- ADD_CHECKPOINT(1000000, "46b690b710a07ea051bc4a6b6842ac37be691089c0f7758cfeec4d5fc0b4a258");
- ADD_CHECKPOINT(1058600, "12904f6b4d9e60fd875674e07147d2c83d6716253f046af7b894c3e81da7e1bd");
+ ADD_CHECKPOINT2(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b", "0x1");
+ ADD_CHECKPOINT2(1000000, "46b690b710a07ea051bc4a6b6842ac37be691089c0f7758cfeec4d5fc0b4a258", "0x7aaad7153");
+ ADD_CHECKPOINT2(1058600, "12904f6b4d9e60fd875674e07147d2c83d6716253f046af7b894c3e81da7e1bd", "0x971efd119");
+ ADD_CHECKPOINT2(1450000, "87562ca6786f41556b8d5b48067303a57dc5ca77155b35199aedaeca1550f5a0", "0xa639e2930e");
return true;
}
if (nettype == STAGENET)
{
- ADD_CHECKPOINT(0, "76ee3cc98646292206cd3e86f74d88b4dcc1d937088645e9b0cbca84b7ce74eb");
- ADD_CHECKPOINT(10000, "1f8b0ce313f8b9ba9a46108bfd285c45ad7c2176871fd41c3a690d4830ce2fd5");
+ ADD_CHECKPOINT2(0, "76ee3cc98646292206cd3e86f74d88b4dcc1d937088645e9b0cbca84b7ce74eb", "0x1");
+ ADD_CHECKPOINT2(10000, "1f8b0ce313f8b9ba9a46108bfd285c45ad7c2176871fd41c3a690d4830ce2fd5", "0x1d73ba");
+ ADD_CHECKPOINT2(550000, "409f68cddd8e74b37469b41c1e61250d81c5776b42264f416d5d27c4626383ed", "0x5f3d4d03e");
return true;
}
- ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148");
- ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381");
- ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d");
- ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876");
- ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2");
- ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25");
- ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6");
- ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c");
- ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3");
- ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698");
- ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2");
- ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb");
- ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063");
- ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553");
- ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61");
- ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf");
- ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131");
- ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8");
- ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d");
- ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831");
- ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02");
- ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5");
- ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd");
- ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60");
- ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337");
- ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f");
- ADD_CHECKPOINT(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721");
- ADD_CHECKPOINT(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903");
- ADD_CHECKPOINT(1150000, "1dd16f626d18e1e988490dfd06de5920e22629c972c58b4d8daddea0038627b2");
- ADD_CHECKPOINT(1200000, "fa7d13a90850882060479d100141ff84286599ae39c3277c8ea784393f882d1f");
- ADD_CHECKPOINT(1300000, "31b34272343a44a9f4ac7de7a8fcf3b7d8a3124d7d6870affd510d2f37e74cd0");
- ADD_CHECKPOINT(1390000, "a8f5649dd4ded60eedab475f2bec8c934681c07e3cf640e9be0617554f13ff6c");
- ADD_CHECKPOINT(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2");
- ADD_CHECKPOINT(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e");
- ADD_CHECKPOINT(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241");
- ADD_CHECKPOINT(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568");
- ADD_CHECKPOINT(1775600, "1c6e01c661dc22cab939e79ec6a5272190624ce8356d2f7b958e4f9a57fdb05e");
- ADD_CHECKPOINT(1856000, "9b57f17f29c71a3acd8a7904b93c41fa6eb8d2b7c73936ce4f1702d14880ba29");
- ADD_CHECKPOINT(1958000, "98a5d6e51afdf3146e0eefb10a66e8648d8d4d5c2742be8835e976ba217c9bb2");
+ ADD_CHECKPOINT2(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148", "0x2");
+ ADD_CHECKPOINT2(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381", "0x2a974");
+ ADD_CHECKPOINT2(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d", "0x35d14b");
+ ADD_CHECKPOINT2(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876", "0x36a0373");
+ ADD_CHECKPOINT2(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2", "0x60a91390");
+ ADD_CHECKPOINT2(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25", "0x1e288793d");
+ ADD_CHECKPOINT2(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6", "0x71f64cce8");
+ ADD_CHECKPOINT2(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c", "0x893044b400");
+ ADD_CHECKPOINT2(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3", "0x5cc113f1076");
+ ADD_CHECKPOINT2(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698", "0x73310a259eb2");
+ ADD_CHECKPOINT2(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2", "0x733154039b97");
+ ADD_CHECKPOINT2(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb", "0x73319dc90cb6");
+ ADD_CHECKPOINT2(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063", "0x75fcc3d85123");
+ ADD_CHECKPOINT2(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553", "0x89cfed0cae3c");
+ ADD_CHECKPOINT2(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61", "0x967d13e5baa9");
+ ADD_CHECKPOINT2(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf", "0x96fb9663ebe7");
+ ADD_CHECKPOINT2(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131", "0x97b9919177bf");
+ ADD_CHECKPOINT2(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8", "0x98a038b612e8");
+ ADD_CHECKPOINT2(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d", "0xac9739634e6d");
+ ADD_CHECKPOINT2(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831", "0x167799549bdda");
+ ADD_CHECKPOINT2(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02", "0x188ce145e4ba9");
+ ADD_CHECKPOINT2(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5", "0x1d9f3759e1554");
+ ADD_CHECKPOINT2(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd", "0x2201e4ee39c2c");
+ ADD_CHECKPOINT2(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60", "0x27565a442d5df");
+ ADD_CHECKPOINT2(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337", "0x2a6334031546e");
+ ADD_CHECKPOINT2(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f", "0x2aefe7f40f5ea");
+ ADD_CHECKPOINT2(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721", "0x2edd71370f0e5");
+ ADD_CHECKPOINT2(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903", "0x390eb0035c53a");
+ ADD_CHECKPOINT2(1150000, "1dd16f626d18e1e988490dfd06de5920e22629c972c58b4d8daddea0038627b2", "0x422d5662e9e37");
+ ADD_CHECKPOINT2(1200000, "fa7d13a90850882060479d100141ff84286599ae39c3277c8ea784393f882d1f", "0x4c73503fc4aa3");
+ ADD_CHECKPOINT2(1300000, "31b34272343a44a9f4ac7de7a8fcf3b7d8a3124d7d6870affd510d2f37e74cd0", "0x723f49bc249d5");
+ ADD_CHECKPOINT2(1390000, "a8f5649dd4ded60eedab475f2bec8c934681c07e3cf640e9be0617554f13ff6c", "0xb4bba65e2841b");
+ ADD_CHECKPOINT2(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2", "0x11a4aabdca9511");
+ ADD_CHECKPOINT2(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e", "0x2819ce9f9e91e5");
+ ADD_CHECKPOINT2(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241", "0x357a590e7dda83");
+ ADD_CHECKPOINT2(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568", "0x474226e475cc3b");
+ ADD_CHECKPOINT2(1775600, "1c6e01c661dc22cab939e79ec6a5272190624ce8356d2f7b958e4f9a57fdb05e", "0x5e3b9d206a27c6");
+ ADD_CHECKPOINT2(1856000, "9b57f17f29c71a3acd8a7904b93c41fa6eb8d2b7c73936ce4f1702d14880ba29", "0x6bde5e1caccee1");
+ ADD_CHECKPOINT2(1958000, "98a5d6e51afdf3146e0eefb10a66e8648d8d4d5c2742be8835e976ba217c9bb2", "0x79dd46d2a0971a");
+ ADD_CHECKPOINT2(2046000, "5e867f0b8baefed9244a681df97fc885d8ab36c3dfcd24c7a3abf3b8ac8b8314", "0x9cb8b6ff2978c6");
+ ADD_CHECKPOINT2(2092500, "c4e00820c9c7989b49153d5e90ae095a18a11d990e82fcc3be54e6ed785472b5", "0xb4e585a31369cb");
return true;
}
diff --git a/src/checkpoints/checkpoints.h b/src/checkpoints/checkpoints.h
index a55b94bf0..029c50548 100644
--- a/src/checkpoints/checkpoints.h
+++ b/src/checkpoints/checkpoints.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,8 +33,10 @@
#include "misc_log_ex.h"
#include "crypto/hash.h"
#include "cryptonote_config.h"
+#include "cryptonote_basic/difficulty.h"
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false);
+#define ADD_CHECKPOINT2(h, hash, difficulty) CHECK_AND_ASSERT(add_checkpoint(h, hash, difficulty), false);
#define JSON_HASH_FILE_NAME "checkpoints.json"
@@ -61,12 +63,13 @@ namespace cryptonote
*
* @param height the height of the block the checkpoint is for
* @param hash_str the hash of the block, as a string
+ * @param difficulty_str the cumulative difficulty of the block, as a string (optional)
*
* @return false if parsing the hash fails, or if the height is a duplicate
* AND the existing checkpoint hash does not match the new one,
* otherwise returns true
*/
- bool add_checkpoint(uint64_t height, const std::string& hash_str);
+ bool add_checkpoint(uint64_t height, const std::string& hash_str, const std::string& difficulty_str = "");
/**
* @brief checks if there is a checkpoint in the future
@@ -134,6 +137,13 @@ namespace cryptonote
const std::map<uint64_t, crypto::hash>& get_points() const;
/**
+ * @brief gets the difficulty checkpoints container
+ *
+ * @return a const reference to the difficulty checkpoints container
+ */
+ const std::map<uint64_t, difficulty_type>& get_difficulty_points() const;
+
+ /**
* @brief checks if our checkpoints container conflicts with another
*
* A conflict refers to a case where both checkpoint sets have a checkpoint
@@ -187,6 +197,7 @@ namespace cryptonote
private:
std::map<uint64_t, crypto::hash> m_points; //!< the checkpoints container
+ std::map<uint64_t, difficulty_type> m_difficulty_points; //!< the difficulty checkpoints container
};
}
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index f06737b31..8e427b6b8 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -86,7 +86,8 @@ set(common_private_headers
updates.h
aligned.h
timings.h
- combinator.h)
+ combinator.h
+ utf8.h)
monero_private_headers(common
${common_private_headers})
diff --git a/src/common/aligned.c b/src/common/aligned.c
index 6982409f7..e3a607f66 100644
--- a/src/common/aligned.c
+++ b/src/common/aligned.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/apply_permutation.h b/src/common/apply_permutation.h
index a4b2c8b78..03effc50e 100644
--- a/src/common/apply_permutation.h
+++ b/src/common/apply_permutation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/base58.cpp b/src/common/base58.cpp
index ac1bf4b29..77b6a642c 100644
--- a/src/common/base58.cpp
+++ b/src/common/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/base58.h b/src/common/base58.h
index 6bf2c3bb7..4a7b02cbc 100644
--- a/src/common/base58.h
+++ b/src/common/base58.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/boost_serialization_helper.h b/src/common/boost_serialization_helper.h
index 2280f3312..4f9cf0518 100644
--- a/src/common/boost_serialization_helper.h
+++ b/src/common/boost_serialization_helper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp
index cae744ea5..42370f543 100644
--- a/src/common/command_line.cpp
+++ b/src/common/command_line.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/command_line.h b/src/common/command_line.h
index b5e3d94a7..b4619905b 100644
--- a/src/common/command_line.h
+++ b/src/common/command_line.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/common_fwd.h b/src/common/common_fwd.h
index 7eaa6cdee..ac8894ba4 100644
--- a/src/common/common_fwd.h
+++ b/src/common/common_fwd.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp
index dc1f335a7..c871177b1 100644
--- a/src/common/dns_utils.cpp
+++ b/src/common/dns_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h
index a6bc7463a..30c4cced2 100644
--- a/src/common/dns_utils.h
+++ b/src/common/dns_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/download.cpp b/src/common/download.cpp
index 2b6a3f9d3..3dd9c3976 100644
--- a/src/common/download.cpp
+++ b/src/common/download.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/download.h b/src/common/download.h
index f8656a59c..19a52a786 100644
--- a/src/common/download.h
+++ b/src/common/download.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/http_connection.h b/src/common/http_connection.h
index 6b4294802..5ee39cdbb 100644
--- a/src/common/http_connection.h
+++ b/src/common/http_connection.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/i18n.cpp b/src/common/i18n.cpp
index 9ac347263..ebc367b3a 100644
--- a/src/common/i18n.cpp
+++ b/src/common/i18n.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/i18n.h b/src/common/i18n.h
index 82a07410d..3bf2f8260 100644
--- a/src/common/i18n.h
+++ b/src/common/i18n.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/json_util.h b/src/common/json_util.h
index 96f4b90e6..38464f7f1 100644
--- a/src/common/json_util.h
+++ b/src/common/json_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/notify.cpp b/src/common/notify.cpp
index e2df5096d..f31100214 100644
--- a/src/common/notify.cpp
+++ b/src/common/notify.cpp
@@ -62,7 +62,7 @@ static void replace(std::vector<std::string> &v, const char *tag, const char *s)
boost::replace_all(str, tag, s);
}
-int Notify::notify(const char *tag, const char *s, ...)
+int Notify::notify(const char *tag, const char *s, ...) const
{
std::vector<std::string> margs = args;
diff --git a/src/common/notify.h b/src/common/notify.h
index f813e8def..65d4e1072 100644
--- a/src/common/notify.h
+++ b/src/common/notify.h
@@ -38,8 +38,12 @@ class Notify
{
public:
Notify(const char *spec);
+ Notify(const Notify&) = default;
+ Notify(Notify&&) = default;
+ Notify& operator=(const Notify&) = default;
+ Notify& operator=(Notify&&) = default;
- int notify(const char *tag, const char *s, ...);
+ int notify(const char *tag, const char *s, ...) const;
private:
std::string filename;
@@ -47,3 +51,4 @@ private:
};
}
+
diff --git a/src/common/password.cpp b/src/common/password.cpp
index 33e1f48fd..019f04c95 100644
--- a/src/common/password.cpp
+++ b/src/common/password.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/password.h b/src/common/password.h
index 2837c70f3..54d97e565 100644
--- a/src/common/password.h
+++ b/src/common/password.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp
index 4408170d1..898701b2f 100644
--- a/src/common/perf_timer.cpp
+++ b/src/common/perf_timer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/perf_timer.h b/src/common/perf_timer.h
index 29a37e655..fb89b78c0 100644
--- a/src/common/perf_timer.h
+++ b/src/common/perf_timer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/pod-class.h b/src/common/pod-class.h
index 200647590..38eae8948 100644
--- a/src/common/pod-class.h
+++ b/src/common/pod-class.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/rpc_client.h b/src/common/rpc_client.h
index dab3e562d..26bcea751 100644
--- a/src/common/rpc_client.h
+++ b/src/common/rpc_client.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/scoped_message_writer.h b/src/common/scoped_message_writer.h
index 546377392..0a5ebe1c9 100644
--- a/src/common/scoped_message_writer.h
+++ b/src/common/scoped_message_writer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/sfinae_helpers.h b/src/common/sfinae_helpers.h
index e9a98bb63..e0778b10f 100644
--- a/src/common/sfinae_helpers.h
+++ b/src/common/sfinae_helpers.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp
index 8d4f8c6f1..828b8f1c8 100644
--- a/src/common/stack_trace.cpp
+++ b/src/common/stack_trace.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/stack_trace.h b/src/common/stack_trace.h
index ae6573885..57f939b2d 100644
--- a/src/common/stack_trace.h
+++ b/src/common/stack_trace.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/threadpool.cpp b/src/common/threadpool.cpp
index 753bf238c..a1737778c 100644
--- a/src/common/threadpool.cpp
+++ b/src/common/threadpool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/threadpool.h b/src/common/threadpool.h
index a49d0e14f..91f9fdf47 100644
--- a/src/common/threadpool.h
+++ b/src/common/threadpool.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/unordered_containers_boost_serialization.h b/src/common/unordered_containers_boost_serialization.h
index 74e2c3f81..67bde676c 100644
--- a/src/common/unordered_containers_boost_serialization.h
+++ b/src/common/unordered_containers_boost_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/updates.cpp b/src/common/updates.cpp
index f620bb53a..c51c4320f 100644
--- a/src/common/updates.cpp
+++ b/src/common/updates.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/updates.h b/src/common/updates.h
index 8fda6d207..0bfe26c3f 100644
--- a/src/common/updates.h
+++ b/src/common/updates.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/utf8.h b/src/common/utf8.h
new file mode 100644
index 000000000..60247f1b2
--- /dev/null
+++ b/src/common/utf8.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <cctype>
+#include <cwchar>
+#include <stdexcept>
+
+namespace tools
+{
+ template<typename T, typename Transform>
+ inline T utf8canonical(const T &s, Transform t = [](wint_t c)->wint_t { return c; })
+ {
+ T sc = "";
+ size_t avail = s.size();
+ const char *ptr = s.data();
+ wint_t cp = 0;
+ int bytes = 1;
+ char wbuf[8], *wptr;
+ while (avail--)
+ {
+ if ((*ptr & 0x80) == 0)
+ {
+ cp = *ptr++;
+ bytes = 1;
+ }
+ else if ((*ptr & 0xe0) == 0xc0)
+ {
+ if (avail < 1)
+ throw std::runtime_error("Invalid UTF-8");
+ cp = (*ptr++ & 0x1f) << 6;
+ cp |= *ptr++ & 0x3f;
+ --avail;
+ bytes = 2;
+ }
+ else if ((*ptr & 0xf0) == 0xe0)
+ {
+ if (avail < 2)
+ throw std::runtime_error("Invalid UTF-8");
+ cp = (*ptr++ & 0xf) << 12;
+ cp |= (*ptr++ & 0x3f) << 6;
+ cp |= *ptr++ & 0x3f;
+ avail -= 2;
+ bytes = 3;
+ }
+ else if ((*ptr & 0xf8) == 0xf0)
+ {
+ if (avail < 3)
+ throw std::runtime_error("Invalid UTF-8");
+ cp = (*ptr++ & 0x7) << 18;
+ cp |= (*ptr++ & 0x3f) << 12;
+ cp |= (*ptr++ & 0x3f) << 6;
+ cp |= *ptr++ & 0x3f;
+ avail -= 3;
+ bytes = 4;
+ }
+ else
+ throw std::runtime_error("Invalid UTF-8");
+
+ cp = t(cp);
+ if (cp <= 0x7f)
+ bytes = 1;
+ else if (cp <= 0x7ff)
+ bytes = 2;
+ else if (cp <= 0xffff)
+ bytes = 3;
+ else if (cp <= 0x10ffff)
+ bytes = 4;
+ else
+ throw std::runtime_error("Invalid code point UTF-8 transformation");
+
+ wptr = wbuf;
+ switch (bytes)
+ {
+ case 1: *wptr++ = cp; break;
+ case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
+ case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
+ case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
+ default: throw std::runtime_error("Invalid UTF-8");
+ }
+ *wptr = 0;
+ sc.append(wbuf, bytes);
+ cp = 0;
+ bytes = 1;
+ }
+ return sc;
+ }
+}
diff --git a/src/common/util.cpp b/src/common/util.cpp
index f1140d1d5..138ac4294 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/util.h b/src/common/util.h
index 25137ab64..0c3409ea1 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/common/varint.h b/src/common/varint.h
index a0d79be28..133622a67 100644
--- a/src/common/varint.h
+++ b/src/common/varint.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 80f1e5d7e..3b33fe90a 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -116,3 +116,6 @@ endif()
# cheat because cmake and ccache hate each other
set_property(SOURCE CryptonightR_template.S PROPERTY LANGUAGE C)
+
+# Must be done last, because it references libraries in this directory
+add_subdirectory(wallet)
diff --git a/src/crypto/blake256.c b/src/crypto/blake256.c
index bb2c5fb40..831a90302 100644
--- a/src/crypto/blake256.c
+++ b/src/crypto/blake256.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/blake256.h b/src/crypto/blake256.h
index 309dbf3ec..5abdb79b9 100644
--- a/src/crypto/blake256.h
+++ b/src/crypto/blake256.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/c_threads.h b/src/crypto/c_threads.h
index 56d680ff8..5b2fcddd3 100644
--- a/src/crypto/c_threads.h
+++ b/src/crypto/c_threads.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h
index a39823e5a..a1158be7e 100644
--- a/src/crypto/chacha.h
+++ b/src/crypto/chacha.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto-ops-data.c b/src/crypto/crypto-ops-data.c
index c9530bb2a..d16fd9429 100644
--- a/src/crypto/crypto-ops-data.c
+++ b/src/crypto/crypto-ops-data.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c
index 5a3d994a6..3110d3ce7 100644
--- a/src/crypto/crypto-ops.c
+++ b/src/crypto/crypto-ops.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h
index 7137437bc..eeb94669b 100644
--- a/src/crypto/crypto-ops.h
+++ b/src/crypto/crypto-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index 0ec992de9..4cfe83d54 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -43,6 +43,8 @@
#include "crypto.h"
#include "hash.h"
+#include "cryptonote_config.h"
+
namespace {
static void local_abort(const char *msg)
{
@@ -261,11 +263,24 @@ namespace crypto {
ec_point comm;
};
+ // Used in v1 tx proofs
+ struct s_comm_2_v1 {
+ hash msg;
+ ec_point D;
+ ec_point X;
+ ec_point Y;
+ };
+
+ // Used in v1/v2 tx proofs
struct s_comm_2 {
hash msg;
ec_point D;
ec_point X;
ec_point Y;
+ hash sep; // domain separation
+ ec_point R;
+ ec_point A;
+ ec_point B;
};
void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
@@ -294,6 +309,7 @@ namespace crypto {
sc_mulsub(&sig.r, &sig.c, &unwrap(sec), &k);
if (!sc_isnonzero((const unsigned char*)sig.r.data))
goto try_again;
+ memwipe(&k, sizeof(k));
}
bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
@@ -320,6 +336,86 @@ namespace crypto {
return sc_isnonzero(&c) == 0;
}
+ // Generate a proof of knowledge of `r` such that (`R = rG` and `D = rA`) or (`R = rB` and `D = rA`) via a Schnorr proof
+ // This handles use cases for both standard addresses and subaddresses
+ //
+ // NOTE: This generates old v1 proofs, and is for TESTING ONLY
+ void crypto_ops::generate_tx_proof_v1(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
+ // sanity check
+ ge_p3 R_p3;
+ ge_p3 A_p3;
+ ge_p3 B_p3;
+ ge_p3 D_p3;
+ if (ge_frombytes_vartime(&R_p3, &R) != 0) throw std::runtime_error("tx pubkey is invalid");
+ if (ge_frombytes_vartime(&A_p3, &A) != 0) throw std::runtime_error("recipient view pubkey is invalid");
+ if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) throw std::runtime_error("recipient spend pubkey is invalid");
+ if (ge_frombytes_vartime(&D_p3, &D) != 0) throw std::runtime_error("key derivation is invalid");
+#if !defined(NDEBUG)
+ {
+ assert(sc_check(&r) == 0);
+ // check R == r*G or R == r*B
+ public_key dbg_R;
+ if (B)
+ {
+ ge_p2 dbg_R_p2;
+ ge_scalarmult(&dbg_R_p2, &r, &B_p3);
+ ge_tobytes(&dbg_R, &dbg_R_p2);
+ }
+ else
+ {
+ ge_p3 dbg_R_p3;
+ ge_scalarmult_base(&dbg_R_p3, &r);
+ ge_p3_tobytes(&dbg_R, &dbg_R_p3);
+ }
+ assert(R == dbg_R);
+ // check D == r*A
+ ge_p2 dbg_D_p2;
+ ge_scalarmult(&dbg_D_p2, &r, &A_p3);
+ public_key dbg_D;
+ ge_tobytes(&dbg_D, &dbg_D_p2);
+ assert(D == dbg_D);
+ }
+#endif
+
+ // pick random k
+ ec_scalar k;
+ random_scalar(k);
+
+ s_comm_2_v1 buf;
+ buf.msg = prefix_hash;
+ buf.D = D;
+
+ if (B)
+ {
+ // compute X = k*B
+ ge_p2 X_p2;
+ ge_scalarmult(&X_p2, &k, &B_p3);
+ ge_tobytes(&buf.X, &X_p2);
+ }
+ else
+ {
+ // compute X = k*G
+ ge_p3 X_p3;
+ ge_scalarmult_base(&X_p3, &k);
+ ge_p3_tobytes(&buf.X, &X_p3);
+ }
+
+ // compute Y = k*A
+ ge_p2 Y_p2;
+ ge_scalarmult(&Y_p2, &k, &A_p3);
+ ge_tobytes(&buf.Y, &Y_p2);
+
+ // sig.c = Hs(Msg || D || X || Y)
+ hash_to_scalar(&buf, sizeof(buf), sig.c);
+
+ // sig.r = k - sig.c*r
+ sc_mulsub(&sig.r, &sig.c, &unwrap(r), &k);
+ }
+
+ // Generate a proof of knowledge of `r` such that (`R = rG` and `D = rA`) or (`R = rB` and `D = rA`) via a Schnorr proof
+ // This handles use cases for both standard addresses and subaddresses
+ //
+ // Generates only proofs for InProofV2 and OutProofV2
void crypto_ops::generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
// sanity check
ge_p3 R_p3;
@@ -361,10 +457,20 @@ namespace crypto {
ec_scalar k;
random_scalar(k);
+ // if B is not present
+ static const ec_point zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
+
s_comm_2 buf;
buf.msg = prefix_hash;
buf.D = D;
-
+ buf.R = R;
+ buf.A = A;
+ if (B)
+ buf.B = *B;
+ else
+ buf.B = zero;
+ cn_fast_hash(config::HASH_KEY_TXPROOF_V2, sizeof(config::HASH_KEY_TXPROOF_V2)-1, buf.sep);
+
if (B)
{
// compute X = k*B
@@ -385,14 +491,17 @@ namespace crypto {
ge_scalarmult(&Y_p2, &k, &A_p3);
ge_tobytes(&buf.Y, &Y_p2);
- // sig.c = Hs(Msg || D || X || Y)
+ // sig.c = Hs(Msg || D || X || Y || sep || R || A || B)
hash_to_scalar(&buf, sizeof(buf), sig.c);
// sig.r = k - sig.c*r
sc_mulsub(&sig.r, &sig.c, &unwrap(r), &k);
+
+ memwipe(&k, sizeof(k));
}
- bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
+ // Verify a proof: either v1 (version == 1) or v2 (version == 2)
+ bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig, const int version) {
// sanity check
ge_p3 R_p3;
ge_p3 A_p3;
@@ -464,14 +573,31 @@ namespace crypto {
ge_p2 Y_p2;
ge_p1p1_to_p2(&Y_p2, &Y_p1p1);
- // compute c2 = Hs(Msg || D || X || Y)
+ // Compute hash challenge
+ // for v1, c2 = Hs(Msg || D || X || Y)
+ // for v2, c2 = Hs(Msg || D || X || Y || sep || R || A || B)
+
+ // if B is not present
+ static const ec_point zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
+
s_comm_2 buf;
buf.msg = prefix_hash;
buf.D = D;
+ buf.R = R;
+ buf.A = A;
+ if (B)
+ buf.B = *B;
+ else
+ buf.B = zero;
+ cn_fast_hash(config::HASH_KEY_TXPROOF_V2, sizeof(config::HASH_KEY_TXPROOF_V2)-1, buf.sep);
ge_tobytes(&buf.X, &X_p2);
ge_tobytes(&buf.Y, &Y_p2);
ec_scalar c2;
- hash_to_scalar(&buf, sizeof(s_comm_2), c2);
+
+ // Hash depends on version
+ if (version == 1) hash_to_scalar(&buf, sizeof(s_comm_2) - 3*sizeof(ec_point) - sizeof(hash), c2);
+ else if (version == 2) hash_to_scalar(&buf, sizeof(s_comm_2), c2);
+ else return false;
// test if c2 == sig.c
sc_sub(&c2, &c2, &sig.c);
@@ -560,6 +686,7 @@ POP_WARNINGS
random_scalar(sig[i].c);
random_scalar(sig[i].r);
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
+ memwipe(&k, sizeof(k));
local_abort("invalid pubkey");
}
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
@@ -573,6 +700,8 @@ POP_WARNINGS
hash_to_scalar(buf.get(), rs_comm_size(pubs_count), h);
sc_sub(&sig[sec_index].c, &h, &sum);
sc_mulsub(&sig[sec_index].r, &sig[sec_index].c, &unwrap(sec), &k);
+
+ memwipe(&k, sizeof(k));
}
bool crypto_ops::check_ring_signature(const hash &prefix_hash, const key_image &image,
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 8ce321f71..7ddc0150f 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -132,8 +132,10 @@ namespace crypto {
friend bool check_signature(const hash &, const public_key &, const signature &);
static void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
- static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
- friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
+ static void generate_tx_proof_v1(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
+ friend void generate_tx_proof_v1(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
+ static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
+ friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
static void generate_key_image(const public_key &, const secret_key &, key_image &);
friend void generate_key_image(const public_key &, const secret_key &, key_image &);
static void generate_ring_signature(const hash &, const key_image &,
@@ -248,8 +250,11 @@ namespace crypto {
inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
crypto_ops::generate_tx_proof(prefix_hash, R, A, B, D, r, sig);
}
- inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
- return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig);
+ inline void generate_tx_proof_v1(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
+ crypto_ops::generate_tx_proof_v1(prefix_hash, R, A, B, D, r, sig);
+ }
+ inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig, const int version) {
+ return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig, version);
}
/* To send money to a key:
diff --git a/src/crypto/crypto_ops_builder/README.md b/src/crypto/crypto_ops_builder/README.md
index 4bb95cc4a..a3acb11e8 100644
--- a/src/crypto/crypto_ops_builder/README.md
+++ b/src/crypto/crypto_ops_builder/README.md
@@ -1,6 +1,6 @@
# Monero
-Copyright (c) 2014-2019, The Monero Project
+Copyright (c) 2014-2020, The Monero Project
## Crypto Ops Builder
diff --git a/src/crypto/crypto_ops_builder/crypto-ops-data.c b/src/crypto/crypto_ops_builder/crypto-ops-data.c
index 45e9923b1..64fd15070 100644
--- a/src/crypto/crypto_ops_builder/crypto-ops-data.c
+++ b/src/crypto/crypto_ops_builder/crypto-ops-data.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/crypto-ops-old.c b/src/crypto/crypto_ops_builder/crypto-ops-old.c
index 89c2ced6e..da85ee534 100644
--- a/src/crypto/crypto_ops_builder/crypto-ops-old.c
+++ b/src/crypto/crypto_ops_builder/crypto-ops-old.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/crypto-ops.h b/src/crypto/crypto_ops_builder/crypto-ops.h
index b4fcfca9c..d719743c4 100644
--- a/src/crypto/crypto_ops_builder/crypto-ops.h
+++ b/src/crypto/crypto_ops_builder/crypto-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
index dfba583f7..08cead175 100644
--- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
+++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
@@ -15,7 +15,7 @@ print("maybe someone smart can replace the sed with perl..")
a = ""
license = textwrap.dedent("""\
- // Copyright (c) 2014-2019, The Monero Project
+ // Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h b/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
index f62ff441d..613b718f5 100644
--- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
+++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/generic-ops.h b/src/crypto/generic-ops.h
index d06726638..9aa7b065a 100644
--- a/src/crypto/generic-ops.h
+++ b/src/crypto/generic-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/groestl.h b/src/crypto/groestl.h
index 6628947dd..7483db9b6 100644
--- a/src/crypto/groestl.h
+++ b/src/crypto/groestl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/groestl_tables.h b/src/crypto/groestl_tables.h
index ca0c4fca6..7bf03afd7 100644
--- a/src/crypto/groestl_tables.h
+++ b/src/crypto/groestl_tables.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-blake.c b/src/crypto/hash-extra-blake.c
index 9bada96f3..4cc915cdd 100644
--- a/src/crypto/hash-extra-blake.c
+++ b/src/crypto/hash-extra-blake.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-groestl.c b/src/crypto/hash-extra-groestl.c
index 57866bf9d..dec21310d 100644
--- a/src/crypto/hash-extra-groestl.c
+++ b/src/crypto/hash-extra-groestl.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-jh.c b/src/crypto/hash-extra-jh.c
index 0dbac4fb5..0604003bd 100644
--- a/src/crypto/hash-extra-jh.c
+++ b/src/crypto/hash-extra-jh.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-skein.c b/src/crypto/hash-extra-skein.c
index 78f48609f..55bd4ddec 100644
--- a/src/crypto/hash-extra-skein.c
+++ b/src/crypto/hash-extra-skein.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h
index d117bb640..7dfc5151d 100644
--- a/src/crypto/hash-ops.h
+++ b/src/crypto/hash-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash.c b/src/crypto/hash.c
index b66f3b010..a917115fe 100644
--- a/src/crypto/hash.c
+++ b/src/crypto/hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash.h b/src/crypto/hash.h
index 27184fa53..4b99bebaa 100644
--- a/src/crypto/hash.h
+++ b/src/crypto/hash.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/initializer.h b/src/crypto/initializer.h
index 75d80f054..e9a7d97e2 100644
--- a/src/crypto/initializer.h
+++ b/src/crypto/initializer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c
index 851c70a25..72d472d8a 100644
--- a/src/crypto/keccak.c
+++ b/src/crypto/keccak.c
@@ -146,7 +146,6 @@ void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md)
#define KECCAK_BLOCKLEN 136
#define KECCAK_WORDS 17
#define KECCAK_DIGESTSIZE 32
-#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0)))
#define KECCAK_PROCESS_BLOCK(st, block) { \
for (int i_ = 0; i_ < KECCAK_WORDS; i_++){ \
((st))[i_] ^= swap64le(((block))[i_]); \
@@ -178,17 +177,10 @@ void keccak_update(KECCAK_CTX * ctx, const uint8_t *in, size_t inlen){
inlen -= left;
}
- const bool is_aligned = IS_ALIGNED_64(in);
while (inlen >= KECCAK_BLOCKLEN) {
- const uint64_t* aligned_message_block;
- if (is_aligned) {
- aligned_message_block = (uint64_t*)in;
- } else {
- memcpy(ctx->message, in, KECCAK_BLOCKLEN);
- aligned_message_block = ctx->message;
- }
+ memcpy(ctx->message, in, KECCAK_BLOCKLEN);
- KECCAK_PROCESS_BLOCK(ctx->hash, aligned_message_block);
+ KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
in += KECCAK_BLOCKLEN;
inlen -= KECCAK_BLOCKLEN;
}
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 766b5f558..1e3d9beff 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/random.h b/src/crypto/random.h
index 21a66d776..8b81e7a66 100644
--- a/src/crypto/random.h
+++ b/src/crypto/random.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c
index 606c67336..1d7f09cab 100644
--- a/src/crypto/rx-slow-hash.c
+++ b/src/crypto/rx-slow-hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/skein_port.h b/src/crypto/skein_port.h
index 1ec07a4d1..94fd44035 100644
--- a/src/crypto/skein_port.h
+++ b/src/crypto/skein_port.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index 88eb751a6..5a773f3cf 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c
index 0a5860f3b..643e95121 100644
--- a/src/crypto/tree-hash.c
+++ b/src/crypto/tree-hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/wallet/CMakeLists.txt b/src/crypto/wallet/CMakeLists.txt
new file mode 100644
index 000000000..4ed986dce
--- /dev/null
+++ b/src/crypto/wallet/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright (c) 2020, The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Possibly user defined values.
+#
+set(MONERO_WALLET_CRYPTO_LIBRARY "auto" CACHE STRING "Select a wallet crypto library")
+
+#
+# If the user specified "auto", detect best library defaulting to internal.
+#
+if (${MONERO_WALLET_CRYPTO_LIBRARY} STREQUAL "auto")
+ monero_crypto_autodetect(AVAILABLE BEST)
+ if (DEFINED BEST)
+ message("Wallet crypto is using ${BEST} backend")
+ set(MONERO_WALLET_CRYPTO_LIBRARY ${BEST})
+ else ()
+ message("Defaulting to internal crypto library for wallet")
+ set(MONERO_WALLET_CRYPTO_LIBRARY "cn")
+ endif ()
+endif ()
+
+#
+# Configure library target "wallet-crypto" - clients will use this as a
+# library dependency which in turn will depend on the crypto library selected.
+#
+if (${MONERO_WALLET_CRYPTO_LIBRARY} STREQUAL "cn")
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/empty.h.in ${MONERO_GENERATED_HEADERS_DIR}/crypto/wallet/ops.h)
+ add_library(wallet-crypto ALIAS cncrypto)
+else ()
+ monero_crypto_generate_header(${MONERO_WALLET_CRYPTO_LIBRARY} "${MONERO_GENERATED_HEADERS_DIR}/crypto/wallet/ops.h")
+ monero_crypto_get_target(${MONERO_WALLET_CRYPTO_LIBRARY} CRYPTO_TARGET)
+ add_library(wallet-crypto $<TARGET_OBJECTS:${CRYPTO_TARGET}>)
+ target_link_libraries(wallet-crypto cncrypto)
+endif ()
+
+
diff --git a/src/crypto/wallet/crypto.h b/src/crypto/wallet/crypto.h
new file mode 100644
index 000000000..a4c5d5a07
--- /dev/null
+++ b/src/crypto/wallet/crypto.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <cstddef>
+#include "crypto/wallet/ops.h"
+
+namespace crypto {
+ namespace wallet {
+// if C functions defined from external/supercop - cmake generates crypto/wallet/ops.h
+#if defined(monero_crypto_generate_key_derivation)
+ inline
+ bool generate_key_derivation(const public_key &tx_pub, const secret_key &view_sec, key_derivation &out)
+ {
+ return monero_crypto_generate_key_derivation(out.data, tx_pub.data, view_sec.data) == 0;
+ }
+
+ inline
+ bool derive_subaddress_public_key(const public_key &output_pub, const key_derivation &d, std::size_t index, public_key &out)
+ {
+ ec_scalar scalar;
+ derivation_to_scalar(d, index, scalar);
+ return monero_crypto_generate_subaddress_public_key(out.data, output_pub.data, scalar.data) == 0;
+ }
+#else
+ using ::crypto::generate_key_derivation;
+ using ::crypto::derive_subaddress_public_key;
+#endif
+ }
+}
diff --git a/src/crypto/wallet/empty.h.in b/src/crypto/wallet/empty.h.in
new file mode 100644
index 000000000..ac252e1bd
--- /dev/null
+++ b/src/crypto/wallet/empty.h.in
@@ -0,0 +1,31 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+// Left empty so internal cryptonote crypto library is used.
diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt
index 59040d8a2..113fd9d86 100644
--- a/src/cryptonote_basic/CMakeLists.txt
+++ b/src/cryptonote_basic/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp
index 02eca289e..b366985ab 100644
--- a/src/cryptonote_basic/account.cpp
+++ b/src/cryptonote_basic/account.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -61,7 +61,8 @@ DISABLE_VS_WARNINGS(4244 4345)
m_device = &hwdev;
MCDEBUG("device", "account_keys::set_device device type: "<<typeid(hwdev).name());
}
- //-----------------------------------------------------------------
+
+ // Generate a derived chacha key
static void derive_key(const crypto::chacha_key &base_key, crypto::chacha_key &key)
{
static_assert(sizeof(base_key) == sizeof(crypto::hash), "chacha key and hash should be the same size");
@@ -70,25 +71,38 @@ DISABLE_VS_WARNINGS(4244 4345)
data[sizeof(base_key)] = config::HASH_KEY_MEMORY;
crypto::generate_chacha_key(data.data(), sizeof(data), key, 1);
}
- //-----------------------------------------------------------------
- static epee::wipeable_string get_key_stream(const crypto::chacha_key &base_key, const crypto::chacha_iv &iv, size_t bytes)
+
+ // Prepare IVs and start chacha for encryption
+ void account_keys::encrypt_wrapper(const crypto::chacha_key &key, const bool all_keys)
{
- // derive a new key
- crypto::chacha_key key;
- derive_key(base_key, key);
+ // Set a fresh IV only for all-key encryption
+ if (all_keys)
+ m_encryption_iv = crypto::rand<crypto::chacha_iv>();
- // chacha
- epee::wipeable_string buffer0(std::string(bytes, '\0'));
- epee::wipeable_string buffer1 = buffer0;
- crypto::chacha20(buffer0.data(), buffer0.size(), key, iv, buffer1.data());
- return buffer1;
+ // Now do the chacha
+ chacha_wrapper(key, all_keys);
}
- //-----------------------------------------------------------------
- void account_keys::xor_with_key_stream(const crypto::chacha_key &key)
+
+ // Start chacha for decryption
+ void account_keys::decrypt_wrapper(const crypto::chacha_key &key, const bool all_keys)
+ {
+ chacha_wrapper(key, all_keys);
+ }
+
+ // Decrypt keys using the legacy method
+ void account_keys::decrypt_legacy(const crypto::chacha_key &key)
{
- // encrypt a large enough byte stream with chacha20
- epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size()));
- const char *ptr = key_stream.data();
+ // Derive domain-separated chacha key
+ crypto::chacha_key derived_key;
+ derive_key(key, derived_key);
+
+ // Build key stream
+ epee::wipeable_string temp(std::string(sizeof(crypto::secret_key)*(2 + m_multisig_keys.size()), '\0'));
+ epee::wipeable_string stream = temp;
+ crypto::chacha20(temp.data(), temp.size(), derived_key, m_encryption_iv, stream.data());
+
+ // Decrypt all keys
+ const char *ptr = stream.data();
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
m_spend_secret_key.data[i] ^= *ptr++;
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
@@ -99,33 +113,39 @@ DISABLE_VS_WARNINGS(4244 4345)
k.data[i] ^= *ptr++;
}
}
- //-----------------------------------------------------------------
- void account_keys::encrypt(const crypto::chacha_key &key)
+
+ // Perform chacha on either the view key or all keys
+ void account_keys::chacha_wrapper(const crypto::chacha_key &key, const bool all_keys)
{
- m_encryption_iv = crypto::rand<crypto::chacha_iv>();
- xor_with_key_stream(key);
- }
- //-----------------------------------------------------------------
- void account_keys::decrypt(const crypto::chacha_key &key)
- {
- xor_with_key_stream(key);
- }
- //-----------------------------------------------------------------
- void account_keys::encrypt_viewkey(const crypto::chacha_key &key)
- {
- // encrypt a large enough byte stream with chacha20
- epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * 2);
- const char *ptr = key_stream.data();
- ptr += sizeof(crypto::secret_key);
- for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
- m_view_secret_key.data[i] ^= *ptr++;
- }
- //-----------------------------------------------------------------
- void account_keys::decrypt_viewkey(const crypto::chacha_key &key)
- {
- encrypt_viewkey(key);
+ // Derive domain-seprated chacha key
+ crypto::chacha_key derived_key;
+ derive_key(key, derived_key);
+
+ // Chacha the specified keys using the appropriate IVs
+ if (all_keys)
+ {
+ // Spend key
+ crypto::secret_key temp_key;
+ chacha20((char *) &m_spend_secret_key, sizeof(crypto::secret_key), derived_key, m_encryption_iv, (char *) &temp_key);
+ memcpy(&m_spend_secret_key, &temp_key, sizeof(crypto::secret_key));
+ memwipe(&temp_key, sizeof(crypto::secret_key));
+
+ // Multisig keys
+ std::vector<crypto::secret_key> temp_keys;
+ temp_keys.reserve(m_multisig_keys.size());
+ temp_keys.resize(m_multisig_keys.size());
+ chacha20((char *) &m_multisig_keys[0], sizeof(crypto::secret_key)*m_multisig_keys.size(), derived_key, m_encryption_iv, (char *) &temp_keys[0]);
+ memcpy(&m_multisig_keys[0], &temp_keys[0], sizeof(crypto::secret_key)*temp_keys.size());
+ memwipe(&temp_keys[0], sizeof(crypto::secret_key)*temp_keys.size());
+ }
+
+ // View key
+ crypto::secret_key temp_key;
+ chacha20((char *) &m_view_secret_key, sizeof(crypto::secret_key), derived_key, m_encryption_iv, (char *) &temp_key);
+ memcpy(&m_view_secret_key, &temp_key, sizeof(crypto::secret_key));
+ memwipe(&temp_key, sizeof(crypto::secret_key));
}
- //-----------------------------------------------------------------
+
account_base::account_base()
{
set_null();
diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h
index abf751b6e..c71c06edd 100644
--- a/src/cryptonote_basic/account.h
+++ b/src/cryptonote_basic/account.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -57,16 +57,15 @@ namespace cryptonote
account_keys& operator=(account_keys const&) = default;
- void encrypt(const crypto::chacha_key &key);
- void decrypt(const crypto::chacha_key &key);
- void encrypt_viewkey(const crypto::chacha_key &key);
- void decrypt_viewkey(const crypto::chacha_key &key);
+ void encrypt_wrapper(const crypto::chacha_key &key, const bool all_keys);
+ void decrypt_wrapper(const crypto::chacha_key &key, const bool all_keys);
+ void decrypt_legacy(const crypto::chacha_key &key);
hw::device& get_device() const ;
void set_device( hw::device &hwdev) ;
private:
- void xor_with_key_stream(const crypto::chacha_key &key);
+ void chacha_wrapper(const crypto::chacha_key &key, const bool all_keys);
};
/************************************************************************/
@@ -100,10 +99,12 @@ namespace cryptonote
void forget_spend_key();
const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
- void encrypt_keys(const crypto::chacha_key &key) { m_keys.encrypt(key); }
- void decrypt_keys(const crypto::chacha_key &key) { m_keys.decrypt(key); }
- void encrypt_viewkey(const crypto::chacha_key &key) { m_keys.encrypt_viewkey(key); }
- void decrypt_viewkey(const crypto::chacha_key &key) { m_keys.decrypt_viewkey(key); }
+ void encrypt_keys(const crypto::chacha_key &key) { m_keys.encrypt_wrapper(key, true); }
+ void encrypt_keys_same_iv(const crypto::chacha_key &key) { m_keys.decrypt_wrapper(key, true); } // encryption with the same IV is the same as decryption due to symmetry
+ void decrypt_keys(const crypto::chacha_key &key) { m_keys.decrypt_wrapper(key, true); }
+ void encrypt_viewkey(const crypto::chacha_key &key) { m_keys.encrypt_wrapper(key, false); }
+ void decrypt_viewkey(const crypto::chacha_key &key) { m_keys.decrypt_wrapper(key, false); }
+ void decrypt_legacy(const crypto::chacha_key &key) { m_keys.decrypt_legacy(key); }
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int /*ver*/)
diff --git a/src/cryptonote_basic/account_boost_serialization.h b/src/cryptonote_basic/account_boost_serialization.h
index 320a960dc..d97a5a854 100644
--- a/src/cryptonote_basic/account_boost_serialization.h
+++ b/src/cryptonote_basic/account_boost_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/blobdatatype.h b/src/cryptonote_basic/blobdatatype.h
index 20f6b2421..6906e0c9d 100644
--- a/src/cryptonote_basic/blobdatatype.h
+++ b/src/cryptonote_basic/blobdatatype.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
index a682bebf2..0c3a94054 100644
--- a/src/cryptonote_basic/connection_context.h
+++ b/src/cryptonote_basic/connection_context.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index e2286ae8c..bc6a378f2 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp
index 9bafcfc86..541393fa9 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.cpp
+++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index c7198a16f..1303670d2 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
index 79ce610a9..6f89cc7ae 100644
--- a/src/cryptonote_basic/cryptonote_boost_serialization.h
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index b3400abc7..3fd059ac1 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -160,6 +160,8 @@ namespace cryptonote
if (tx.version >= 2 && !is_coinbase(tx))
{
rct::rctSig &rv = tx.rct_signatures;
+ if (rv.type == rct::RCTTypeNull)
+ return true;
if (rv.outPk.size() != tx.vout.size())
{
LOG_PRINT_L1("Failed to parse transaction from blob, bad outPk size in tx " << get_transaction_hash(tx));
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index d1b24d950..5639e38d0 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp
index 859173aa5..dbc2e534a 100644
--- a/src/cryptonote_basic/difficulty.cpp
+++ b/src/cryptonote_basic/difficulty.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h
index 771deb04c..7f5ea4597 100644
--- a/src/cryptonote_basic/difficulty.h
+++ b/src/cryptonote_basic/difficulty.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/events.h b/src/cryptonote_basic/events.h
new file mode 100644
index 000000000..6c6742215
--- /dev/null
+++ b/src/cryptonote_basic/events.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include "crypto/hash.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+
+namespace cryptonote
+{
+ /*! Transactions are expensive to move or copy (lots of 32-byte internal
+ buffers). This allows `cryptonote::core` to do a single notification for
+ a vector of transactions, without having to move/copy duplicate or invalid
+ transactions. */
+ struct txpool_event
+ {
+ cryptonote::transaction tx;
+ crypto::hash hash;
+ bool res; //!< Listeners must ignore `tx` when this is false.
+ };
+}
diff --git a/src/cryptonote_basic/fwd.h b/src/cryptonote_basic/fwd.h
new file mode 100644
index 000000000..d54223461
--- /dev/null
+++ b/src/cryptonote_basic/fwd.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+namespace cryptonote
+{
+ struct block;
+ class transaction;
+ struct txpool_event;
+}
diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
index dfeca27b4..7a5161bc8 100644
--- a/src/cryptonote_basic/hardfork.cpp
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h
index 987dcc75a..5800c31b5 100644
--- a/src/cryptonote_basic/hardfork.h
+++ b/src/cryptonote_basic/hardfork.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index c1e8365ac..34a559b83 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
index ce50d674e..3cbc4e5a4 100644
--- a/src/cryptonote_basic/miner.h
+++ b/src/cryptonote_basic/miner.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/subaddress_index.h b/src/cryptonote_basic/subaddress_index.h
index 99933e229..3f5f120d9 100644
--- a/src/cryptonote_basic/subaddress_index.h
+++ b/src/cryptonote_basic/subaddress_index.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h
index ecb4c6040..50f2e1438 100644
--- a/src/cryptonote_basic/tx_extra.h
+++ b/src/cryptonote_basic/tx_extra.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h
index ec5f604a5..2535cba95 100644
--- a/src/cryptonote_basic/verification_context.h
+++ b/src/cryptonote_basic/verification_context.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 81dc15dee..8c4e61d4d 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -117,6 +117,11 @@
#define CRYPTONOTE_NOISE_BYTES 3*1024 // 3 KiB
#define CRYPTONOTE_NOISE_CHANNELS 2 // Max outgoing connections per zone used for noise/covert sending
+// Both below are in seconds. The idea is to delay forwarding from i2p/tor
+// to ipv4/6, such that 2+ incoming connections _could_ have sent the tx
+#define CRYPTONOTE_FORWARD_DELAY_BASE (CRYPTONOTE_NOISE_MIN_DELAY + CRYPTONOTE_NOISE_DELAY_RANGE)
+#define CRYPTONOTE_FORWARD_DELAY_AVERAGE (CRYPTONOTE_FORWARD_DELAY_BASE + (CRYPTONOTE_FORWARD_DELAY_BASE / 2))
+
#define CRYPTONOTE_MAX_FRAGMENTS 20 // ~20 * NOISE_BYTES max payload size for covert/noise send
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 1000
@@ -219,6 +224,7 @@ namespace config
const unsigned char HASH_KEY_RPC_PAYMENT_NONCE = 0x58;
const unsigned char HASH_KEY_MEMORY = 'k';
const unsigned char HASH_KEY_MULTISIG[] = {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ const unsigned char HASH_KEY_TXPROOF_V2[] = "TXPROOF_V2";
namespace testnet
{
diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt
index cb3875878..0be8b544e 100644
--- a/src/cryptonote_core/CMakeLists.txt
+++ b/src/cryptonote_core/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 2571e4203..b0726981c 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -32,6 +32,7 @@
#include <cstdio>
#include <boost/filesystem.hpp>
#include <boost/range/adaptor/reversed.hpp>
+#include <boost/format.hpp>
#include "include_base_utils.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
@@ -86,7 +87,7 @@ DISABLE_VS_WARNINGS(4267)
//------------------------------------------------------------------
Blockchain::Blockchain(tx_memory_pool& tx_pool) :
- m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
+ m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_reset_timestamps_and_difficulties_height(true), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
m_long_term_block_weights_window(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
m_long_term_effective_median_block_weight(0),
@@ -427,6 +428,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
if (num_popped_blocks > 0)
{
m_timestamps_and_difficulties_height = 0;
+ m_reset_timestamps_and_difficulties_height = true;
m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
uint64_t top_block_height;
crypto::hash top_block_hash = get_tail_id(top_block_height);
@@ -439,6 +441,15 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
m_long_term_block_weights_cache_rolling_median = epee::misc_utils::rolling_median_t<uint64_t>(m_long_term_block_weights_window);
}
+ bool difficulty_ok;
+ uint64_t difficulty_recalc_height;
+ std::tie(difficulty_ok, difficulty_recalc_height) = check_difficulty_checkpoints();
+ if (!difficulty_ok)
+ {
+ MERROR("Difficulty drift detected!");
+ recalculate_difficulties(difficulty_recalc_height);
+ }
+
{
db_txn_guard txn_guard(m_db, m_db->is_read_only());
if (!update_next_cumulative_weight_limit())
@@ -567,6 +578,7 @@ block Blockchain::pop_block_from_blockchain()
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
+ m_reset_timestamps_and_difficulties_height = true;
block popped_block;
std::vector<transaction> popped_txs;
@@ -644,6 +656,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
+ m_reset_timestamps_and_difficulties_height = true;
invalidate_block_template_cache();
m_db->reset();
m_db->drop_alt_blocks();
@@ -812,12 +825,20 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
// less blocks than desired if there aren't enough.
difficulty_type Blockchain::get_difficulty_for_next_block()
{
+ LOG_PRINT_L3("Blockchain::" << __func__);
+
+ std::stringstream ss;
+ bool print = false;
+
+ int done = 0;
+ ss << "get_difficulty_for_next_block: height " << m_db->height() << std::endl;
if (m_fixed_difficulty)
{
return m_db->height() ? m_fixed_difficulty : 1;
}
- LOG_PRINT_L3("Blockchain::" << __func__);
+start:
+ difficulty_type D = 0;
crypto::hash top_hash = get_tail_id();
{
@@ -826,21 +847,32 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
// something a bit out of date, but that's fine since anything which
// requires the blockchain lock will have acquired it in the first place,
// and it will be unlocked only when called from the getinfo RPC
+ ss << "Locked, tail id " << top_hash << ", cached is " << m_difficulty_for_next_block_top_hash << std::endl;
if (top_hash == m_difficulty_for_next_block_top_hash)
- return m_difficulty_for_next_block;
+ {
+ ss << "Same, using cached diff " << m_difficulty_for_next_block << std::endl;
+ D = m_difficulty_for_next_block;
+ }
}
CRITICAL_REGION_LOCAL(m_blockchain_lock);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties;
uint64_t height;
- top_hash = get_tail_id(height); // get it again now that we have the lock
- ++height; // top block height to blockchain height
+ auto new_top_hash = get_tail_id(height); // get it again now that we have the lock
+ ++height;
+ if (!(new_top_hash == top_hash)) D=0;
+ ss << "Re-locked, height " << height << ", tail id " << new_top_hash << (new_top_hash == top_hash ? "" : " (different)") << std::endl;
+ top_hash = new_top_hash;
+
// ND: Speedup
// 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
// then when the next block difficulty is queried, push the latest height data and
// pop the oldest one from the list. This only requires 1x read per height instead
// of doing 735 (DIFFICULTY_BLOCKS_COUNT).
+ bool check = false;
+ if (m_reset_timestamps_and_difficulties_height)
+ m_timestamps_and_difficulties_height = 0;
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= DIFFICULTY_BLOCKS_COUNT)
{
uint64_t index = height - 1;
@@ -855,8 +887,12 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
m_timestamps_and_difficulties_height = height;
timestamps = m_timestamps;
difficulties = m_difficulties;
+ check = true;
}
- else
+ //else
+ std::vector<uint64_t> timestamps_from_cache = timestamps;
+ std::vector<difficulty_type> difficulties_from_cache = difficulties;
+
{
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT));
if (offset == 0)
@@ -869,27 +905,179 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
timestamps.reserve(height - offset);
difficulties.reserve(height - offset);
}
+ ss << "Looking up " << (height - offset) << " from " << offset << std::endl;
for (; offset < height; offset++)
{
timestamps.push_back(m_db->get_block_timestamp(offset));
difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
}
+ if (check) if (timestamps != timestamps_from_cache || difficulties !=difficulties_from_cache)
+ {
+ ss << "Inconsistency XXX:" << std::endl;
+ ss << "top hash: "<<top_hash << std::endl;
+ ss << "timestamps: " << timestamps_from_cache.size() << " from cache, but " << timestamps.size() << " without" << std::endl;
+ ss << "difficulties: " << difficulties_from_cache.size() << " from cache, but " << difficulties.size() << " without" << std::endl;
+ ss << "timestamps_from_cache:" << std::endl; for (const auto &v :timestamps_from_cache) ss << " " << v << std::endl;
+ ss << "timestamps:" << std::endl; for (const auto &v :timestamps) ss << " " << v << std::endl;
+ ss << "difficulties_from_cache:" << std::endl; for (const auto &v :difficulties_from_cache) ss << " " << v << std::endl;
+ ss << "difficulties:" << std::endl; for (const auto &v :difficulties) ss << " " << v << std::endl;
+
+ uint64_t dbh = m_db->height();
+ uint64_t sh = dbh < 10000 ? 0 : dbh - 10000;
+ ss << "History from -10k at :" << dbh << ", from " << sh << std::endl;
+ for (uint64_t h = sh; h < dbh; ++h)
+ {
+ uint64_t ts = m_db->get_block_timestamp(h);
+ difficulty_type d = m_db->get_block_cumulative_difficulty(h);
+ ss << " " << h << " " << ts << " " << d << std::endl;
+ }
+ print = true;
+ }
m_timestamps_and_difficulties_height = height;
m_timestamps = timestamps;
m_difficulties = difficulties;
}
+
size_t target = get_difficulty_target();
difficulty_type diff = next_difficulty(timestamps, difficulties, target);
CRITICAL_REGION_LOCAL1(m_difficulty_lock);
m_difficulty_for_next_block_top_hash = top_hash;
m_difficulty_for_next_block = diff;
+ if (D && D != diff)
+ {
+ ss << "XXX Mismatch at " << height << "/" << top_hash << "/" << get_tail_id() << ": cached " << D << ", real " << diff << std::endl;
+ print = true;
+ }
+
+ ++done;
+ if (done == 1 && D && D != diff)
+ {
+ print = true;
+ ss << "Might be a race. Let's see what happens if we try again..." << std::endl;
+ epee::misc_utils::sleep_no_w(100);
+ goto start;
+ }
+ ss << "Diff for " << top_hash << ": " << diff << std::endl;
+ if (print)
+ {
+ MGINFO("START DUMP");
+ MGINFO(ss.str());
+ MGINFO("END DUMP");
+ MGINFO("Please send moneromooo on Freenode the contents of this log, from a couple dozen lines before START DUMP to END DUMP");
+ }
return diff;
}
//------------------------------------------------------------------
+std::pair<bool, uint64_t> Blockchain::check_difficulty_checkpoints() const
+{
+ uint64_t res = 0;
+ for (const std::pair<uint64_t, difficulty_type>& i : m_checkpoints.get_difficulty_points())
+ {
+ if (i.first >= m_db->height())
+ break;
+ if (m_db->get_block_cumulative_difficulty(i.first) != i.second)
+ return {false, res};
+ res = i.first;
+ }
+ return {true, res};
+}
+//------------------------------------------------------------------
+size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_height_opt)
+{
+ if (m_fixed_difficulty)
+ {
+ return 0;
+ }
+ LOG_PRINT_L3("Blockchain::" << __func__);
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
+
+ const uint64_t start_height = start_height_opt ? *start_height_opt : check_difficulty_checkpoints().second;
+ const uint64_t top_height = m_db->height() - 1;
+ MGINFO("Recalculating difficulties from height " << start_height << " to height " << top_height);
+
+ std::vector<uint64_t> timestamps;
+ std::vector<difficulty_type> difficulties;
+ timestamps.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
+ difficulties.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
+ if (start_height > 1)
+ {
+ for (uint64_t i = 0; i < DIFFICULTY_BLOCKS_COUNT; ++i)
+ {
+ uint64_t height = start_height - 1 - i;
+ if (height == 0)
+ break;
+ timestamps.insert(timestamps.begin(), m_db->get_block_timestamp(height));
+ difficulties.insert(difficulties.begin(), m_db->get_block_cumulative_difficulty(height));
+ }
+ }
+ difficulty_type last_cum_diff = start_height <= 1 ? start_height : difficulties.back();
+ uint64_t drift_start_height = 0;
+ std::vector<difficulty_type> new_cumulative_difficulties;
+ for (uint64_t height = start_height; height <= top_height; ++height)
+ {
+ size_t target = get_ideal_hard_fork_version(height) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
+ difficulty_type recalculated_diff = next_difficulty(timestamps, difficulties, target);
+
+ boost::multiprecision::uint256_t recalculated_cum_diff_256 = boost::multiprecision::uint256_t(recalculated_diff) + last_cum_diff;
+ CHECK_AND_ASSERT_THROW_MES(recalculated_cum_diff_256 <= std::numeric_limits<difficulty_type>::max(), "Difficulty overflow!");
+ difficulty_type recalculated_cum_diff = recalculated_cum_diff_256.convert_to<difficulty_type>();
+
+ if (drift_start_height == 0)
+ {
+ difficulty_type existing_cum_diff = m_db->get_block_cumulative_difficulty(height);
+ if (recalculated_cum_diff != existing_cum_diff)
+ {
+ drift_start_height = height;
+ new_cumulative_difficulties.reserve(top_height + 1 - height);
+ LOG_ERROR("Difficulty drift found at height:" << height << ", hash:" << m_db->get_block_hash_from_height(height) << ", existing:" << existing_cum_diff << ", recalculated:" << recalculated_cum_diff);
+ }
+ }
+ if (drift_start_height > 0)
+ {
+ new_cumulative_difficulties.push_back(recalculated_cum_diff);
+ if (height % 100000 == 0)
+ LOG_ERROR(boost::format("%llu / %llu (%.1f%%)") % height % top_height % (100 * (height - drift_start_height) / float(top_height - drift_start_height)));
+ }
+
+ if (height > 0)
+ {
+ timestamps.push_back(m_db->get_block_timestamp(height));
+ difficulties.push_back(recalculated_cum_diff);
+ }
+ if (timestamps.size() > DIFFICULTY_BLOCKS_COUNT)
+ {
+ CHECK_AND_ASSERT_THROW_MES(timestamps.size() == DIFFICULTY_BLOCKS_COUNT + 1, "Wrong timestamps size: " << timestamps.size());
+ timestamps.erase(timestamps.begin());
+ difficulties.erase(difficulties.begin());
+ }
+ last_cum_diff = recalculated_cum_diff;
+ }
+
+ if (drift_start_height > 0)
+ {
+ LOG_ERROR("Writing to the DB...");
+ try
+ {
+ m_db->correct_block_cumulative_difficulties(drift_start_height, new_cumulative_difficulties);
+ }
+ catch (const std::exception& e)
+ {
+ LOG_ERROR("Error correcting cumulative difficulties from height " << drift_start_height << ", what = " << e.what());
+ }
+ LOG_ERROR("Corrected difficulties for " << new_cumulative_difficulties.size() << " blocks");
+ // clear cache
+ m_difficulty_for_next_block_top_hash = crypto::null_hash;
+ m_timestamps_and_difficulties_height = 0;
+ }
+
+ return new_cumulative_difficulties.size();
+}
+//------------------------------------------------------------------
std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
{
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
uint64_t height = m_db->height();
if (blocks > height)
blocks = height;
@@ -914,6 +1102,7 @@ bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain,
}
m_timestamps_and_difficulties_height = 0;
+ m_reset_timestamps_and_difficulties_height = true;
// remove blocks from blockchain until we get back to where we should be.
while (m_db->height() != rollback_height)
@@ -950,6 +1139,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
+ m_reset_timestamps_and_difficulties_height = true;
// if empty alt chain passed (not sure how that could happen), return false
CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed");
@@ -1044,10 +1234,15 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
reorg_notify->notify("%s", std::to_string(split_height).c_str(), "%h", std::to_string(m_db->height()).c_str(),
"%n", std::to_string(m_db->height() - split_height).c_str(), "%d", std::to_string(discarded_blocks).c_str(), NULL);
- std::shared_ptr<tools::Notify> block_notify = m_block_notify;
- if (block_notify)
- for (const auto &bei: alt_chain)
- block_notify->notify("%s", epee::string_tools::pod_to_hex(get_block_hash(bei.bl)).c_str(), NULL);
+ for (const auto& notifier : m_block_notifiers)
+ {
+ std::size_t notify_height = split_height;
+ for (const auto& bei: alt_chain)
+ {
+ notifier(notify_height, {std::addressof(bei.bl), 1});
+ ++notify_height;
+ }
+ }
MGINFO_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db->height());
return true;
@@ -1639,6 +1834,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
+ m_reset_timestamps_and_difficulties_height = true;
uint64_t block_height = get_block_height(b);
if(0 == block_height)
{
@@ -2493,6 +2689,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
}
db_rtxn_guard rtxn_guard(m_db);
+ total_height = get_current_blockchain_height();
blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height)));
CHECK_AND_ASSERT_MES(m_db->get_blocks_from(start_height, 3, max_count, FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE, blocks, pruned, true, get_miner_tx_hash),
false, "Error getting blocks");
@@ -4044,12 +4241,9 @@ leave:
get_difficulty_for_next_block(); // just to cache it
invalidate_block_template_cache();
- if (notify)
- {
- std::shared_ptr<tools::Notify> block_notify = m_block_notify;
- if (block_notify)
- block_notify->notify("%s", epee::string_tools::pod_to_hex(id).c_str(), NULL);
- }
+
+ for (const auto& notifier: m_block_notifiers)
+ notifier(new_height - 1, {std::addressof(bl), 1});
return true;
}
@@ -4317,7 +4511,14 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
try
{
if (m_batch_success)
+ {
m_db->batch_stop();
+ if (m_reset_timestamps_and_difficulties_height)
+ {
+ m_timestamps_and_difficulties_height = 0;
+ m_reset_timestamps_and_difficulties_height = false;
+ }
+ }
else
m_db->batch_abort();
success = true;
@@ -4933,6 +5134,15 @@ void Blockchain::set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint
m_max_prepare_blocks_threads = maxthreads;
}
+void Blockchain::add_block_notify(boost::function<void(std::uint64_t, epee::span<const block>)>&& notify)
+{
+ if (notify)
+ {
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ m_block_notifiers.push_back(std::move(notify));
+ }
+}
+
void Blockchain::safesyncmode(const bool onoff)
{
/* all of this is no-op'd if the user set a specific
@@ -5028,7 +5238,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
-static const char expected_block_hashes_hash[] = "fce1dc7c17f7679f5f447df206b8f5fe2ef6b1a2845e59f650850a0ef00d265f";
+static const char expected_block_hashes_hash[] = "8b48d259d4b1126801b1f329683a26e1d16237420197cd3ccc76af2c55a36e83";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 3a89cc5df..703dd6400 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -30,6 +30,7 @@
#pragma once
#include <boost/asio/io_service.hpp>
+#include <boost/function/function_fwd.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/list.hpp>
@@ -310,6 +311,22 @@ namespace cryptonote
difficulty_type get_difficulty_for_next_block();
/**
+ * @brief check currently stored difficulties against difficulty checkpoints
+ *
+ * @return {flag, height} flag: true if all difficulty checkpoints pass, height: the last checkpoint height before the difficulty drift bug starts
+ */
+ std::pair<bool, uint64_t> check_difficulty_checkpoints() const;
+
+ /**
+ * @brief recalculate difficulties for blocks after the last difficulty checkpoints to circumvent the annoying 'difficulty drift' bug
+ *
+ * @param start_height: if omitted, starts recalculation from the last difficulty checkpoint
+ *
+ * @return number of blocks whose difficulties got corrected
+ */
+ size_t recalculate_difficulties(boost::optional<uint64_t> start_height = boost::none);
+
+ /**
* @brief adds a block to the blockchain
*
* Adds a new block to the blockchain. If the block's parent is not the
@@ -748,7 +765,7 @@ namespace cryptonote
*
* @param notify the notify object to call at every new block
*/
- void set_block_notify(const std::shared_ptr<tools::Notify> &notify) { m_block_notify = notify; }
+ void add_block_notify(boost::function<void(std::uint64_t, epee::span<const block>)> &&notify);
/**
* @brief sets a reorg notify object to call for every reorg
@@ -1067,6 +1084,7 @@ namespace cryptonote
std::vector<uint64_t> m_timestamps;
std::vector<difficulty_type> m_difficulties;
uint64_t m_timestamps_and_difficulties_height;
+ bool m_reset_timestamps_and_difficulties_height;
uint64_t m_long_term_block_weights_window;
uint64_t m_long_term_effective_median_block_weight;
mutable crypto::hash m_long_term_block_weights_cache_tip_hash;
@@ -1108,7 +1126,11 @@ namespace cryptonote
bool m_batch_success;
- std::shared_ptr<tools::Notify> m_block_notify;
+ /* `boost::function` is used because the implementation never allocates if
+ the callable object has a single `std::shared_ptr` or `std::weap_ptr`
+ internally. Whereas, the libstdc++ `std::function` will allocate. */
+
+ std::vector<boost::function<void(std::uint64_t, epee::span<const block>)>> m_block_notifiers;
std::shared_ptr<tools::Notify> m_reorg_notify;
// for prepare_handle_incoming_blocks
diff --git a/src/cryptonote_core/blockchain_storage_boost_serialization.h b/src/cryptonote_core/blockchain_storage_boost_serialization.h
index cfeb5acfc..b5c14d53c 100644
--- a/src/cryptonote_core/blockchain_storage_boost_serialization.h
+++ b/src/cryptonote_core/blockchain_storage_boost_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 3ff3c77e2..8e30d6676 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -41,6 +41,7 @@ using namespace epee;
#include "common/download.h"
#include "common/threadpool.h"
#include "common/command_line.h"
+#include "cryptonote_basic/events.h"
#include "warnings.h"
#include "crypto/crypto.h"
#include "cryptonote_config.h"
@@ -51,6 +52,7 @@ using namespace epee;
#include "ringct/rctTypes.h"
#include "blockchain_db/blockchain_db.h"
#include "ringct/rctSigs.h"
+#include "rpc/zmq_pub.h"
#include "common/notify.h"
#include "hardforks/hardforks.h"
#include "version.h"
@@ -262,15 +264,22 @@ namespace cryptonote
{
m_blockchain_storage.set_enforce_dns_checkpoints(enforce_dns);
}
+ //-----------------------------------------------------------------------------------
+ void core::set_txpool_listener(boost::function<void(std::vector<txpool_event>)> zmq_pub)
+ {
+ CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
+ m_zmq_pub = std::move(zmq_pub);
+ }
+
//-----------------------------------------------------------------------------------------------
- bool core::update_checkpoints()
+ bool core::update_checkpoints(const bool skip_dns /* = false */)
{
if (m_nettype != MAINNET || m_disable_dns_checkpoints) return true;
if (m_checkpoints_updating.test_and_set()) return true;
bool res = true;
- if (time(NULL) - m_last_dns_checkpoints_update >= 3600)
+ if (!skip_dns && time(NULL) - m_last_dns_checkpoints_update >= 3600)
{
res = m_blockchain_storage.update_checkpoints(m_checkpoints_path, true);
m_last_dns_checkpoints_update = time(NULL);
@@ -614,7 +623,20 @@ namespace cryptonote
try
{
if (!command_line::is_arg_defaulted(vm, arg_block_notify))
- m_blockchain_storage.set_block_notify(std::shared_ptr<tools::Notify>(new tools::Notify(command_line::get_arg(vm, arg_block_notify).c_str())));
+ {
+ struct hash_notify
+ {
+ tools::Notify cmdline;
+
+ void operator()(std::uint64_t, epee::span<const block> blocks) const
+ {
+ for (const block bl : blocks)
+ cmdline.notify("%s", epee::string_tools::pod_to_hex(get_block_hash(bl)).c_str(), NULL);
+ }
+ };
+
+ m_blockchain_storage.add_block_notify(hash_notify{{command_line::get_arg(vm, arg_block_notify).c_str()}});
+ }
}
catch (const std::exception &e)
{
@@ -650,7 +672,7 @@ namespace cryptonote
r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty, get_checkpoints);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
- r = m_mempool.init(max_txpool_weight);
+ r = m_mempool.init(max_txpool_weight, m_nettype == FAKECHAIN);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
// now that we have a valid m_blockchain_storage, we can clean out any
@@ -669,7 +691,8 @@ namespace cryptonote
// load json & DNS checkpoints, and verify them
// with respect to what blocks we already have
- CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
+ const bool skip_dns_checkpoints = !command_line::get_arg(vm, arg_dns_checkpoints);
+ CHECK_AND_ASSERT_MES(update_checkpoints(skip_dns_checkpoints), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
// DNS versions checking
if (check_updates_string == "disabled")
@@ -956,8 +979,7 @@ namespace cryptonote
return false;
}
- struct result { bool res; cryptonote::transaction tx; crypto::hash hash; };
- std::vector<result> results(tx_blobs.size());
+ std::vector<txpool_event> results(tx_blobs.size());
CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
@@ -1022,6 +1044,7 @@ namespace cryptonote
if (!tx_info.empty())
handle_incoming_tx_accumulated_batch(tx_info, tx_relay == relay_method::block);
+ bool valid_events = false;
bool ok = true;
it = tx_blobs.begin();
for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
@@ -1044,10 +1067,18 @@ namespace cryptonote
{MERROR_VER("Transaction verification impossible: " << results[i].hash);}
if(tvc[i].m_added_to_pool)
+ {
MDEBUG("tx added: " << results[i].hash);
+ valid_events = true;
+ }
+ else
+ results[i].res = false;
}
- return ok;
+ if (valid_events && m_zmq_pub && matches_category(tx_relay, relay_category::legacy))
+ m_zmq_pub(std::move(results));
+
+ return ok;
CATCH_ENTRY_L0("core::handle_incoming_txs()", false);
}
//-----------------------------------------------------------------------------------------------
@@ -1272,6 +1303,7 @@ namespace cryptonote
{
NOTIFY_NEW_TRANSACTIONS::request public_req{};
NOTIFY_NEW_TRANSACTIONS::request private_req{};
+ NOTIFY_NEW_TRANSACTIONS::request stem_req{};
for (auto& tx : txs)
{
switch (std::get<2>(tx))
@@ -1282,6 +1314,9 @@ namespace cryptonote
case relay_method::local:
private_req.txs.push_back(std::move(std::get<1>(tx)));
break;
+ case relay_method::forward:
+ stem_req.txs.push_back(std::move(std::get<1>(tx)));
+ break;
case relay_method::block:
case relay_method::fluff:
case relay_method::stem:
@@ -1299,6 +1334,8 @@ namespace cryptonote
get_protocol()->relay_transactions(public_req, source, epee::net_utils::zone::public_, relay_method::fluff);
if (!private_req.txs.empty())
get_protocol()->relay_transactions(private_req, source, epee::net_utils::zone::invalid, relay_method::local);
+ if (!stem_req.txs.empty())
+ get_protocol()->relay_transactions(stem_req, source, epee::net_utils::zone::public_, relay_method::stem);
}
return true;
}
@@ -1308,9 +1345,9 @@ namespace cryptonote
std::vector<crypto::hash> tx_hashes{};
tx_hashes.resize(tx_blobs.size());
- cryptonote::transaction tx{};
for (std::size_t i = 0; i < tx_blobs.size(); ++i)
{
+ cryptonote::transaction tx{};
if (!parse_and_validate_tx_from_blob(tx_blobs[i], tx, tx_hashes[i]))
{
LOG_ERROR("Failed to parse relayed transaction");
@@ -1655,42 +1692,17 @@ namespace cryptonote
m_starter_message_showed = true;
}
- m_fork_moaner.do_call(boost::bind(&core::check_fork_time, this));
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this));
m_blockchain_pruning_interval.do_call(boost::bind(&core::update_blockchain_pruning, this));
+ m_diff_recalc_interval.do_call(boost::bind(&core::recalculate_difficulties, this));
m_miner.on_idle();
m_mempool.on_idle();
return true;
}
//-----------------------------------------------------------------------------------------------
- bool core::check_fork_time()
- {
- if (m_nettype == FAKECHAIN)
- return true;
-
- HardFork::State state = m_blockchain_storage.get_hard_fork_state();
- el::Level level;
- switch (state) {
- case HardFork::LikelyForked:
- level = el::Level::Warning;
- MCLOG_RED(level, "global", "**********************************************************************");
- MCLOG_RED(level, "global", "Last scheduled hard fork is too far in the past.");
- MCLOG_RED(level, "global", "We are most likely forked from the network. Daemon update needed now.");
- MCLOG_RED(level, "global", "**********************************************************************");
- break;
- case HardFork::UpdateNeeded:
- level = el::Level::Info;
- MCLOG(level, "global", el::Color::Default, "Last scheduled hard fork time suggests a daemon update will be released within the next couple months.");
- break;
- default:
- break;
- }
- return true;
- }
- //-----------------------------------------------------------------------------------------------
uint8_t core::get_ideal_hard_fork_version() const
{
return get_blockchain_storage().get_ideal_hard_fork_version();
@@ -1924,6 +1936,12 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
+ bool core::recalculate_difficulties()
+ {
+ m_blockchain_storage.recalculate_difficulties();
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
void core::flush_bad_txs_cache()
{
bad_semantics_txes_lock.lock();
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 255645efc..a53596c2c 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -32,9 +32,11 @@
#include <ctime>
+#include <boost/function.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
+#include "cryptonote_basic/fwd.h"
#include "cryptonote_core/i_core_events.h"
#include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
#include "cryptonote_protocol/enums.h"
@@ -48,6 +50,7 @@
#include "warnings.h"
#include "crypto/hash.h"
#include "span.h"
+#include "rpc/fwd.h"
PUSH_WARNINGS
DISABLE_VS_WARNINGS(4355)
@@ -446,6 +449,13 @@ namespace cryptonote
void set_enforce_dns_checkpoints(bool enforce_dns);
/**
+ * @brief set a listener for txes being added to the txpool
+ *
+ * @param callable to notify, or empty function to disable.
+ */
+ void set_txpool_listener(boost::function<void(std::vector<txpool_event>)> zmq_pub);
+
+ /**
* @brief set whether or not to enable or disable DNS checkpoints
*
* @param disble whether to disable DNS checkpoints
@@ -699,7 +709,7 @@ namespace cryptonote
*
* @note see Blockchain::update_checkpoints()
*/
- bool update_checkpoints();
+ bool update_checkpoints(const bool skip_dns = false);
/**
* @brief tells the daemon to wind down operations and stop running
@@ -1001,18 +1011,6 @@ namespace cryptonote
bool check_tx_inputs_keyimages_domain(const transaction& tx) const;
/**
- * @brief checks HardFork status and prints messages about it
- *
- * Checks the status of HardFork and logs/prints if an update to
- * the daemon is necessary.
- *
- * @note see Blockchain::get_hard_fork_state and HardFork::State
- *
- * @return true
- */
- bool check_fork_time();
-
- /**
* @brief attempts to relay any transactions in the mempool which need it
*
* @return true
@@ -1040,6 +1038,13 @@ namespace cryptonote
*/
bool check_block_rate();
+ /**
+ * @brief recalculate difficulties after the last difficulty checklpoint to circumvent the annoying 'difficulty drift' bug
+ *
+ * @return true
+ */
+ bool recalculate_difficulties();
+
bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing)
uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so
@@ -1065,6 +1070,7 @@ namespace cryptonote
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate
epee::math_helper::once_a_time_seconds<60*60*5, true> m_blockchain_pruning_interval; //!< interval for incremental blockchain pruning
+ epee::math_helper::once_a_time_seconds<60*60*24*7, false> m_diff_recalc_interval; //!< interval for recalculating difficulties
std::atomic<bool> m_starter_message_showed; //!< has the "daemon will sync now" message been shown?
@@ -1102,7 +1108,12 @@ namespace cryptonote
bool m_fluffy_blocks_enabled;
bool m_offline;
+ /* `boost::function` is used because the implementation never allocates if
+ the callable object has a single `std::shared_ptr` or `std::weap_ptr`
+ internally. Whereas, the libstdc++ `std::function` will allocate. */
+
std::shared_ptr<tools::Notify> m_block_rate_notify;
+ boost::function<void(std::vector<txpool_event>)> m_zmq_pub;
};
}
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 3dd29dd1b..7ea7e81d9 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index 309e4177f..3622029e0 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_core/i_core_events.h b/src/cryptonote_core/i_core_events.h
index f49fbdf07..03394d785 100644
--- a/src/cryptonote_core/i_core_events.h
+++ b/src/cryptonote_core/i_core_events.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 469319824..7cb0e4062 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -91,6 +91,8 @@ namespace cryptonote
time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
float const ACCEPT_THRESHOLD = 1.0f;
+ constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE};
+
// a kind of increasing backoff within min/max bounds
uint64_t get_relay_delay(time_t now, time_t received)
{
@@ -116,7 +118,7 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
- tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_cookie(0)
+ tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false)
{
}
@@ -309,8 +311,14 @@ namespace cryptonote
if (meta.upgrade_relay_method(tx_relay) || !existing_tx) // synchronize with embargo timer or stem/fluff out-of-order messages
{
+ using clock = std::chrono::system_clock;
+ auto last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max();
+ if (tx_relay == relay_method::forward)
+ last_relayed_time = clock::to_time_t(clock::now() + crypto::random_poisson_seconds{forward_delay_average}());
+ // else the `set_relayed` function will adjust the time accordingly later
+
//update transactions container
- meta.last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max();
+ meta.last_relayed_time = last_relayed_time;
meta.receive_time = receive_time;
meta.weight = tx_weight;
meta.fee = fee;
@@ -341,7 +349,7 @@ namespace cryptonote
tvc.m_added_to_pool = true;
static_assert(unsigned(relay_method::none) == 0, "expected relay_method::none value to be zero");
- if(meta.fee > 0)
+ if(meta.fee > 0 && tx_relay != relay_method::forward)
tvc.m_relay = tx_relay;
}
@@ -722,28 +730,46 @@ namespace cryptonote
//TODO: investigate whether boolean return is appropriate
bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) const
{
+ std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps;
+ const uint64_t now = time(NULL);
+
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- const uint64_t now = time(NULL);
+ LockedTXN lock(m_blockchain.get_db());
txs.reserve(m_blockchain.get_txpool_tx_count());
- m_blockchain.for_all_txpool_txes([this, now, &txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *){
+ m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *){
// 0 fee transactions are never relayed
if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay)
{
- if (!meta.dandelionpp_stem && now - meta.last_relayed_time <= get_relay_delay(now, meta.receive_time))
- return true;
- if (meta.dandelionpp_stem && meta.last_relayed_time < now) // for dandelion++ stem, this value is the embargo timeout
- return true;
+ const relay_method tx_relay = meta.get_relay_method();
+ switch (tx_relay)
+ {
+ case relay_method::stem:
+ case relay_method::forward:
+ if (meta.last_relayed_time > now)
+ return true; // continue to next tx
+ change_timestamps.emplace_back(txid, meta);
+ break;
+ default:
+ case relay_method::none:
+ return true;
+ case relay_method::local:
+ case relay_method::fluff:
+ case relay_method::block:
+ if (now - meta.last_relayed_time <= get_relay_delay(now, meta.receive_time))
+ return true; // continue to next tx
+ break;
+ }
// if the tx is older than half the max lifetime, we don't re-relay it, to avoid a problem
// mentioned by smooth where nodes would flush txes at slightly different times, causing
// flushed txes to be re-added when received from a node which was just about to flush it
- uint64_t max_age = meta.kept_by_block ? CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME : CRYPTONOTE_MEMPOOL_TX_LIVETIME;
+ uint64_t max_age = (tx_relay == relay_method::block) ? CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME : CRYPTONOTE_MEMPOOL_TX_LIVETIME;
if (now - meta.receive_time <= max_age / 2)
{
try
{
- txs.emplace_back(txid, m_blockchain.get_txpool_tx_blob(txid, relay_category::all), meta.get_relay_method());
+ txs.emplace_back(txid, m_blockchain.get_txpool_tx_blob(txid, relay_category::all), tx_relay);
}
catch (const std::exception &e)
{
@@ -754,6 +780,18 @@ namespace cryptonote
}
return true;
}, false, relay_category::relayable);
+
+ for (auto& elem : change_timestamps)
+ {
+ /* These transactions are still in forward or stem state, so the field
+ represents the next time a relay should be attempted. Will be
+ overwritten when the state is upgraded to stem, fluff or block. This
+ function is only called every ~2 minutes, so this resetting should be
+ unnecessary, but is primarily a precaution against potential changes
+ to the callback routines. */
+ elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time);
+ m_blockchain.update_txpool_tx(elem.first, elem.second);
+ }
return true;
}
//---------------------------------------------------------------------------------
@@ -1121,7 +1159,7 @@ namespace cryptonote
// See `insert_key_images`.
if (1 < found->second.size() || *(found->second.cbegin()) != txid)
return true;
- return m_blockchain.txpool_tx_matches_category(txid, relay_category::broadcasted);
+ return m_blockchain.txpool_tx_matches_category(txid, relay_category::legacy);
}
return false;
}
@@ -1351,13 +1389,18 @@ namespace cryptonote
for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
{
txpool_tx_meta_t meta;
- if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta) && !meta.matches(relay_category::legacy))
+ if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
{
MERROR(" failed to find tx meta");
continue;
}
- LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase));
+ LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
+ if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem))
+ {
+ LOG_PRINT_L2(" tx relay method is " << (unsigned)meta.get_relay_method());
+ continue;
+ }
if (meta.pruned)
{
LOG_PRINT_L2(" tx is pruned");
@@ -1522,7 +1565,7 @@ namespace cryptonote
return n_removed;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::init(size_t max_txpool_weight)
+ bool tx_memory_pool::init(size_t max_txpool_weight, bool mine_stem_txes)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
@@ -1578,6 +1621,7 @@ namespace cryptonote
lock.commit();
}
+ m_mine_stem_txes = mine_stem_txes;
m_cookie = 0;
// Ignore deserialization error
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 292d427e2..8955d7551 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -205,10 +205,11 @@ namespace cryptonote
* @brief loads pool state (if any) from disk, and initializes pool
*
* @param max_txpool_weight the max weight in bytes
+ * @param mine_stem_txes whether to mine txes in stem relay mode
*
* @return true
*/
- bool init(size_t max_txpool_weight = 0);
+ bool init(size_t max_txpool_weight = 0, bool mine_stem_txes = false);
/**
* @brief attempts to save the transaction pool state to disk
@@ -603,6 +604,7 @@ private:
size_t m_txpool_max_weight;
size_t m_txpool_weight;
+ bool m_mine_stem_txes;
mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache;
diff --git a/src/cryptonote_core/tx_sanity_check.cpp b/src/cryptonote_core/tx_sanity_check.cpp
index e99982def..ca870779e 100644
--- a/src/cryptonote_core/tx_sanity_check.cpp
+++ b/src/cryptonote_core/tx_sanity_check.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_core/tx_sanity_check.h b/src/cryptonote_core/tx_sanity_check.h
index 4a469462f..15c5476ee 100644
--- a/src/cryptonote_core/tx_sanity_check.h
+++ b/src/cryptonote_core/tx_sanity_check.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_protocol/CMakeLists.txt b/src/cryptonote_protocol/CMakeLists.txt
index bfcf42767..d28b44bb7 100644
--- a/src/cryptonote_protocol/CMakeLists.txt
+++ b/src/cryptonote_protocol/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp
index 67f0b3e5d..bbde91c1f 100644
--- a/src/cryptonote_protocol/block_queue.cpp
+++ b/src/cryptonote_protocol/block_queue.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_protocol/block_queue.h b/src/cryptonote_protocol/block_queue.h
index 93c6532e7..57d2a6490 100644
--- a/src/cryptonote_protocol/block_queue.h
+++ b/src/cryptonote_protocol/block_queue.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index 76b57afd3..9687b07a6 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp
index 225418980..42774f2cb 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer in monero.cc project)
/// @brief This is the place to implement our handlers for protocol network actions, e.g. for ratelimit for download-requests
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index e2ad3727f..89860fe41 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote)
/// @brief This is the original cryptonote protocol network-events handler, modified by us
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -51,7 +51,8 @@ PUSH_WARNINGS
DISABLE_VS_WARNINGS(4355)
#define LOCALHOST_INT 2130706433
-#define CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT 500
+#define CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT 100
+static_assert(CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT >= BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4, "Invalid CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT");
namespace cryptonote
{
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index f8e032fde..bd14fe0a7 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote)
/// @brief This is the original cryptonote protocol network-events handler, modified by us
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -308,9 +308,9 @@ namespace cryptonote
if (version >= 6 && version != hshd.top_version)
{
if (version < hshd.top_version && version == m_core.get_ideal_hard_fork_version())
- MCLOG_RED(el::Level::Warning, "global", context << " peer claims higher version than we think (" <<
+ MDEBUG(context << " peer claims higher version than we think (" <<
(unsigned)hshd.top_version << " for " << (hshd.current_height - 1) << " instead of " << (unsigned)version <<
- ") - we may be forked from the network and a software upgrade may be needed");
+ ") - we may be forked from the network and a software upgrade may be needed, or that peer is broken or malicious");
return false;
}
}
@@ -793,6 +793,12 @@ namespace cryptonote
int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes), block hash " << arg.block_hash);
+ if (context.m_state == cryptonote_connection_context::state_before_handshake)
+ {
+ LOG_ERROR_CCONTEXT("Requested fluffy tx before handshake, dropping connection");
+ drop_connection(context, false, false);
+ return 1;
+ }
std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
std::vector<cryptonote::blobdata> local_txs;
@@ -884,6 +890,8 @@ namespace cryptonote
int t_cryptonote_protocol_handler<t_core>::handle_notify_get_txpool_complement(int command, NOTIFY_GET_TXPOOL_COMPLEMENT::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_GET_TXPOOL_COMPLEMENT (" << arg.hashes.size() << " txes)");
+ if(context.m_state != cryptonote_connection_context::state_normal)
+ return 1;
std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
std::vector<cryptonote::blobdata> local_txs;
@@ -927,7 +935,19 @@ namespace cryptonote
return 1;
}
- relay_method tx_relay;
+ /* If the txes were received over i2p/tor, the default is to "forward"
+ with a randomized delay to further enhance the "white noise" behavior,
+ potentially making it harder for ISP-level spies to determine which
+ inbound link sent the tx. If the sender disabled "white noise" over
+ i2p/tor, then the sender is "fluffing" (to only outbound) i2p/tor
+ connections with the `dandelionpp_fluff` flag set. The receiver (hidden
+ service) will immediately fluff in that scenario (i.e. this assumes that a
+ sybil spy will be unable to link an IP to an i2p/tor connection). */
+
+ const epee::net_utils::zone zone = context.m_remote_address.get_zone();
+ relay_method tx_relay = zone == epee::net_utils::zone::public_ ?
+ relay_method::stem : relay_method::forward;
+
std::vector<blobdata> stem_txs{};
std::vector<blobdata> fluff_txs{};
if (arg.dandelionpp_fluff)
@@ -936,10 +956,7 @@ namespace cryptonote
fluff_txs.reserve(arg.txs.size());
}
else
- {
- tx_relay = relay_method::stem;
stem_txs.reserve(arg.txs.size());
- }
for (auto& tx : arg.txs)
{
@@ -962,6 +979,7 @@ namespace cryptonote
fluff_txs.push_back(std::move(tx));
break;
default:
+ case relay_method::forward: // not supposed to happen here
case relay_method::none:
break;
}
@@ -987,6 +1005,12 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
+ if (context.m_state == cryptonote_connection_context::state_before_handshake)
+ {
+ LOG_ERROR_CCONTEXT("Requested objects before handshake, dropping connection");
+ drop_connection(context, false, false);
+ return 1;
+ }
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
if (arg.blocks.size() > CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT)
{
@@ -1717,6 +1741,12 @@ skip:
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
+ if (context.m_state == cryptonote_connection_context::state_before_handshake)
+ {
+ LOG_ERROR_CCONTEXT("Requested chain before handshake, dropping connection");
+ drop_connection(context, false, false);
+ return 1;
+ }
NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
if(!m_core.find_blockchain_supplement(arg.block_ids, !arg.prune, r))
{
@@ -1907,6 +1937,10 @@ skip:
const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
if (local_stripe == 0)
return false;
+ // don't request pre-bulletprooof pruned blocks, we can't reconstruct their weight (yet)
+ static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
+ if (first_block_height + nblocks - 1 < bp_fork_height)
+ return false;
// assumes the span size is less or equal to the stripe size
bool full_data_needed = tools::get_pruning_stripe(first_block_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe
|| tools::get_pruning_stripe(first_block_height + nblocks - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe;
@@ -2083,7 +2117,8 @@ skip:
skip_unneeded_hashes(context, false);
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
- bool sync_pruned_blocks = m_sync_pruned_blocks && m_core.get_blockchain_pruning_seed();
+ static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
+ bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
if (span.second > 0)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
index 11184299d..1c7635fd8 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_protocol/enums.h b/src/cryptonote_protocol/enums.h
index a3a52b83f..c0c495837 100644
--- a/src/cryptonote_protocol/enums.h
+++ b/src/cryptonote_protocol/enums.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -37,6 +37,7 @@ namespace cryptonote
{
none = 0, //!< Received via RPC with `do_not_relay` set
local, //!< Received via RPC; trying to send over i2p/tor, etc.
+ forward, //!< Received over i2p/tor; timer delayed before ipv4/6 public broadcast
stem, //!< Received/send over network using Dandelion++ stem
fluff, //!< Received/sent over network using Dandelion++ fluff
block //!< Received in block, takes precedence over others
diff --git a/src/cryptonote_protocol/fwd.h b/src/cryptonote_protocol/fwd.h
index 616b48be3..e7722c2f4 100644
--- a/src/cryptonote_protocol/fwd.h
+++ b/src/cryptonote_protocol/fwd.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp
index 127801092..7c482156f 100644
--- a/src/cryptonote_protocol/levin_notify.cpp
+++ b/src/cryptonote_protocol/levin_notify.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -357,11 +357,15 @@ namespace levin
return true;
});
- // Always send txs in stem mode over i2p/tor, see comments in `send_txs` below.
+ /* Always send with `fluff` flag, even over i2p/tor. The hidden service
+ will disable the forwarding delay and immediately fluff. The i2p/tor
+ network is therefore replacing the sybil protection of Dandelion++.
+ Dandelion++ stem phase over i2p/tor is also worth investigating
+ (with/without "noise"?). */
for (auto& connection : connections)
{
std::sort(connection.first.begin(), connection.first.end()); // don't leak receive order
- make_payload_send_txs(*zone_->p2p, std::move(connection.first), connection.second, zone_->pad_txs, zone_->is_public);
+ make_payload_send_txs(*zone_->p2p, std::move(connection.first), connection.second, zone_->pad_txs, true);
}
if (next_flush != std::chrono::steady_clock::time_point::max())
@@ -811,12 +815,11 @@ namespace levin
case relay_method::block:
return false;
case relay_method::stem:
- tx_relay = relay_method::fluff; // don't set stempool embargo when skipping to fluff
- /* fallthrough */
+ case relay_method::forward:
case relay_method::local:
if (zone_->is_public)
{
- // this will change a local tx to stem or fluff ...
+ // this will change a local/forward tx to stem or fluff ...
zone_->strand.dispatch(
dandelionpp_notify{zone_, std::addressof(core), std::move(txs), source}
);
@@ -824,6 +827,11 @@ namespace levin
}
/* fallthrough */
case relay_method::fluff:
+ /* If sending stem/forward/local txes over non public networks,
+ continue to claim that relay mode even though it used the "fluff"
+ routine. A "fluff" over i2p/tor is not the same as a "fluff" over
+ ipv4/6. Marking it as "fluff" here will make the tx immediately
+ visible externally from this node, which is not desired. */
core.on_transactions_relayed(epee::to_span(txs), tx_relay);
zone_->strand.dispatch(fluff_notify{zone_, std::move(txs), source});
break;
diff --git a/src/cryptonote_protocol/levin_notify.h b/src/cryptonote_protocol/levin_notify.h
index 641f1f956..957794b12 100644
--- a/src/cryptonote_protocol/levin_notify.h
+++ b/src/cryptonote_protocol/levin_notify.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index d9bfd9a20..b95c0ac88 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h
index d089d4e47..6c3e163e6 100644
--- a/src/daemon/command_line_args.h
+++ b/src/daemon/command_line_args.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -121,6 +121,10 @@ namespace daemon_args
return val;
}
};
+ const command_line::arg_descriptor<std::vector<std::string>> arg_zmq_pub = {
+ "zmq-pub"
+ , "Address for ZMQ pub - tcp://ip:port or ipc://path"
+ };
const command_line::arg_descriptor<bool> arg_zmq_rpc_disabled = {
"no-zmq"
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 3a4081e39..504b104b0 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index 8b85dcf69..64e4c301b 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -6,7 +6,7 @@
*/
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 7fae77c30..b335116de 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/command_server.h b/src/daemon/command_server.h
index da532223e..946d55b8c 100644
--- a/src/daemon/command_server.h
+++ b/src/daemon/command_server.h
@@ -9,7 +9,7 @@ Passing RPC commands:
*/
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/core.h b/src/daemon/core.h
index 9a3579e20..804d7474d 100644
--- a/src/daemon/core.h
+++ b/src/daemon/core.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 056f2f320..99430b2b0 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,16 +34,17 @@
#include "misc_log_ex.h"
#include "daemon/daemon.h"
#include "rpc/daemon_handler.h"
+#include "rpc/zmq_pub.h"
#include "rpc/zmq_server.h"
#include "common/password.h"
#include "common/util.h"
+#include "cryptonote_basic/events.h"
#include "daemon/core.h"
#include "daemon/p2p.h"
#include "daemon/protocol.h"
#include "daemon/rpc.h"
#include "daemon/command_server.h"
-#include "daemon/command_server.h"
#include "daemon/command_line_args.h"
#include "net/net_ssl.h"
#include "version.h"
@@ -57,6 +58,17 @@ using namespace epee;
namespace daemonize {
+struct zmq_internals
+{
+ explicit zmq_internals(t_core& core, t_p2p& p2p)
+ : rpc_handler{core.get(), p2p.get()}
+ , server{rpc_handler}
+ {}
+
+ cryptonote::rpc::DaemonHandler rpc_handler;
+ cryptonote::rpc::ZmqServer server;
+};
+
struct t_internals {
private:
t_protocol protocol;
@@ -64,6 +76,7 @@ public:
t_core core;
t_p2p p2p;
std::vector<std::unique_ptr<t_rpc>> rpcs;
+ std::unique_ptr<zmq_internals> zmq;
t_internals(
boost::program_options::variables_map const & vm
@@ -71,6 +84,7 @@ public:
: core{vm}
, protocol{vm, core, command_line::get_arg(vm, cryptonote::arg_offline)}
, p2p{vm, protocol}
+ , zmq{nullptr}
{
// Handle circular dependencies
protocol.set_p2p_endpoint(p2p.get());
@@ -87,6 +101,28 @@ public:
auto restricted_rpc_port = command_line::get_arg(vm, restricted_rpc_port_arg);
rpcs.emplace_back(new t_rpc{vm, core, p2p, true, restricted_rpc_port, "restricted", true});
}
+
+ if (!command_line::get_arg(vm, daemon_args::arg_zmq_rpc_disabled))
+ {
+ zmq.reset(new zmq_internals{core, p2p});
+
+ const std::string zmq_port = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_port);
+ const std::string zmq_address = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_ip);
+
+ if (!zmq->server.init_rpc(zmq_address, zmq_port))
+ throw std::runtime_error{"Failed to add TCP socket(" + zmq_address + ":" + zmq_port + ") to ZMQ RPC Server"};
+
+ std::shared_ptr<cryptonote::listener::zmq_pub> shared;
+ const std::vector<std::string> zmq_pub = command_line::get_arg(vm, daemon_args::arg_zmq_pub);
+ if (!zmq_pub.empty() && !(shared = zmq->server.init_pub(epee::to_span(zmq_pub))))
+ throw std::runtime_error{"Failed to initialize zmq_pub"};
+
+ if (shared)
+ {
+ core.get().get_blockchain_storage().add_block_notify(cryptonote::listener::zmq_pub::chain_main{shared});
+ core.get().set_txpool_listener(cryptonote::listener::zmq_pub::txpool_add{shared});
+ }
+ }
}
};
@@ -104,9 +140,6 @@ t_daemon::t_daemon(
: mp_internals{new t_internals{vm}},
public_rpc_port(public_rpc_port)
{
- zmq_rpc_bind_port = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_port);
- zmq_rpc_bind_address = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_ip);
- zmq_rpc_disabled = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_disabled);
}
t_daemon::~t_daemon() = default;
@@ -170,31 +203,8 @@ bool t_daemon::run(bool interactive)
rpc_commands->start_handling(std::bind(&daemonize::t_daemon::stop_p2p, this));
}
- cryptonote::rpc::DaemonHandler rpc_daemon_handler(mp_internals->core.get(), mp_internals->p2p.get());
- cryptonote::rpc::ZmqServer zmq_server(rpc_daemon_handler);
-
- if (!zmq_rpc_disabled)
- {
- if (!zmq_server.addTCPSocket(zmq_rpc_bind_address, zmq_rpc_bind_port))
- {
- LOG_ERROR(std::string("Failed to add TCP Socket (") + zmq_rpc_bind_address
- + ":" + zmq_rpc_bind_port + ") to ZMQ RPC Server");
-
- if (rpc_commands)
- rpc_commands->stop_handling();
-
- for(auto& rpc : mp_internals->rpcs)
- rpc->stop();
-
- return false;
- }
-
- MINFO("Starting ZMQ server...");
- zmq_server.run();
-
- MINFO(std::string("ZMQ server started at ") + zmq_rpc_bind_address
- + ":" + zmq_rpc_bind_port + ".");
- }
+ if (mp_internals->zmq)
+ mp_internals->zmq->server.run();
else
MINFO("ZMQ server disabled");
@@ -209,8 +219,8 @@ bool t_daemon::run(bool interactive)
if (rpc_commands)
rpc_commands->stop_handling();
- if (!zmq_rpc_disabled)
- zmq_server.stop();
+ if (mp_internals->zmq)
+ mp_internals->zmq->server.stop();
for(auto& rpc : mp_internals->rpcs)
rpc->stop();
diff --git a/src/daemon/daemon.h b/src/daemon/daemon.h
index c0efb68ee..2eb2019ce 100644
--- a/src/daemon/daemon.h
+++ b/src/daemon/daemon.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -44,9 +44,6 @@ private:
private:
std::unique_ptr<t_internals> mp_internals;
uint16_t public_rpc_port;
- std::string zmq_rpc_bind_address;
- std::string zmq_rpc_bind_port;
- bool zmq_rpc_disabled;
public:
t_daemon(
boost::program_options::variables_map const & vm,
diff --git a/src/daemon/executor.cpp b/src/daemon/executor.cpp
index 3719a253d..f9ba3b493 100644
--- a/src/daemon/executor.cpp
+++ b/src/daemon/executor.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/executor.h b/src/daemon/executor.h
index 61e4e1bbf..a7235711c 100644
--- a/src/daemon/executor.h
+++ b/src/daemon/executor.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index 3e25636d8..f2ae6dcc3 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -107,6 +107,20 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
return rpc_port;
}
+#ifdef WIN32
+bool isFat32(const wchar_t* root_path)
+{
+ std::vector<wchar_t> fs(MAX_PATH + 1);
+ if (!::GetVolumeInformationW(root_path, nullptr, 0, nullptr, 0, nullptr, &fs[0], MAX_PATH))
+ {
+ MERROR("Failed to get '" << root_path << "' filesystem name. Error code: " << ::GetLastError());
+ return false;
+ }
+
+ return wcscmp(L"FAT32", &fs[0]) == 0;
+}
+#endif
+
int main(int argc, char const * argv[])
{
try {
@@ -140,6 +154,7 @@ int main(int argc, char const * argv[])
command_line::add_arg(core_settings, daemon_args::arg_public_node);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_ip);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_port);
+ command_line::add_arg(core_settings, daemon_args::arg_zmq_pub);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_disabled);
daemonizer::init_options(hidden_options, visible_options);
@@ -233,6 +248,13 @@ int main(int argc, char const * argv[])
boost::filesystem::path data_dir = boost::filesystem::absolute(
command_line::get_arg(vm, cryptonote::arg_data_dir));
+#ifdef WIN32
+ if (isFat32(data_dir.root_name().c_str()))
+ {
+ MERROR("Data directory resides on FAT32 volume that has 4GiB file size limit, blockchain might get corrupted.");
+ }
+#endif
+
// FIXME: not sure on windows implementation default, needs further review
//bf::path relative_path_base = daemonizer::get_relative_path_base(vm);
bf::path relative_path_base = data_dir;
diff --git a/src/daemon/p2p.h b/src/daemon/p2p.h
index 267b99c89..f68efccc2 100644
--- a/src/daemon/p2p.h
+++ b/src/daemon/p2p.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h
index 51a2bce1f..6b03c169a 100644
--- a/src/daemon/protocol.h
+++ b/src/daemon/protocol.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h
index 6f545a3b7..af48bcc45 100644
--- a/src/daemon/rpc.h
+++ b/src/daemon/rpc.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 034d49918..77dfe332f 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -511,7 +511,7 @@ bool t_rpc_command_executor::show_status() {
}
std::stringstream str;
- str << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections")
+ str << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %u(out)+%u(in) connections")
% (unsigned long long)ires.height
% (unsigned long long)net_height
% get_sync_percentage(ires)
@@ -521,7 +521,6 @@ bool t_rpc_command_executor::show_status() {
% get_mining_speed(cryptonote::difficulty_type(ires.wide_difficulty) / ires.target)
% (unsigned)hfres.version
% get_fork_extra_info(hfres.earliest_height, net_height, ires.target)
- % (hfres.state == cryptonote::HardFork::Ready ? "up to date" : hfres.state == cryptonote::HardFork::UpdateNeeded ? "update needed" : "out of date, likely forked")
% (unsigned)ires.outgoing_connections_count
% (unsigned)ires.incoming_connections_count
;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 66ada6f1f..6fb5d6903 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -6,7 +6,7 @@
*/
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemonizer/CMakeLists.txt b/src/daemonizer/CMakeLists.txt
index d540adc10..462d40531 100644
--- a/src/daemonizer/CMakeLists.txt
+++ b/src/daemonizer/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/daemonizer/daemonizer.h b/src/daemonizer/daemonizer.h
index a45a2b44f..442861cdb 100644
--- a/src/daemonizer/daemonizer.h
+++ b/src/daemonizer/daemonizer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemonizer/posix_daemonizer.inl b/src/daemonizer/posix_daemonizer.inl
index 9ec09c678..76ef467ca 100644
--- a/src/daemonizer/posix_daemonizer.inl
+++ b/src/daemonizer/posix_daemonizer.inl
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemonizer/posix_fork.h b/src/daemonizer/posix_fork.h
index 27b4ac18d..d841df0fc 100644
--- a/src/daemonizer/posix_fork.h
+++ b/src/daemonizer/posix_fork.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemonizer/windows_daemonizer.inl b/src/daemonizer/windows_daemonizer.inl
index c6cd474fd..67c8a2855 100644
--- a/src/daemonizer/windows_daemonizer.inl
+++ b/src/daemonizer/windows_daemonizer.inl
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemonizer/windows_service.cpp b/src/daemonizer/windows_service.cpp
index 7d53b07c7..01be6b247 100644
--- a/src/daemonizer/windows_service.cpp
+++ b/src/daemonizer/windows_service.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemonizer/windows_service.h b/src/daemonizer/windows_service.h
index 12429c78a..091041391 100644
--- a/src/daemonizer/windows_service.h
+++ b/src/daemonizer/windows_service.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/daemonizer/windows_service_runner.h b/src/daemonizer/windows_service_runner.h
index 703795ce9..eb72df66d 100644
--- a/src/daemonizer/windows_service_runner.h
+++ b/src/daemonizer/windows_service_runner.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt
index 03c2b3e20..7b21123f6 100644
--- a/src/debug_utilities/CMakeLists.txt
+++ b/src/debug_utilities/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/debug_utilities/cn_deserialize.cpp b/src/debug_utilities/cn_deserialize.cpp
index 89c9db02e..dd4701e4f 100644
--- a/src/debug_utilities/cn_deserialize.cpp
+++ b/src/debug_utilities/cn_deserialize.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/debug_utilities/dns_checks.cpp b/src/debug_utilities/dns_checks.cpp
index 3c9daa769..76b66c6cb 100644
--- a/src/debug_utilities/dns_checks.cpp
+++ b/src/debug_utilities/dns_checks.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/debug_utilities/object_sizes.cpp b/src/debug_utilities/object_sizes.cpp
index 302f0a206..bffff0882 100644
--- a/src/debug_utilities/object_sizes.cpp
+++ b/src/debug_utilities/object_sizes.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt
index 0b0686f61..ff2afba4b 100644
--- a/src/device/CMakeLists.txt
+++ b/src/device/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -72,6 +72,7 @@ target_link_libraries(device
${HIDAPI_LIBRARIES}
cncrypto
ringct_basic
+ wallet-crypto
${OPENSSL_CRYPTO_LIBRARIES}
${Boost_SERIALIZATION_LIBRARY}
PRIVATE
diff --git a/src/device/device.cpp b/src/device/device.cpp
index fbd77dab9..4821abdcf 100644
--- a/src/device/device.cpp
+++ b/src/device/device.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/device.hpp b/src/device/device.hpp
index ecc4849bf..ef973c9f4 100644
--- a/src/device/device.hpp
+++ b/src/device/device.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/device_cold.hpp b/src/device/device_cold.hpp
index 22708c46a..d435b448c 100644
--- a/src/device/device_cold.hpp
+++ b/src/device/device_cold.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp
index 47156cbce..096cb35ba 100644
--- a/src/device/device_default.cpp
+++ b/src/device/device_default.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -32,6 +32,7 @@
#include "device_default.hpp"
#include "int-util.h"
+#include "crypto/wallet/crypto.h"
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/subaddress_index.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
@@ -120,7 +121,7 @@ namespace hw {
/* ======================================================================= */
bool device_default::derive_subaddress_public_key(const crypto::public_key &out_key, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_key) {
- return crypto::derive_subaddress_public_key(out_key, derivation, output_index,derived_key);
+ return crypto::wallet::derive_subaddress_public_key(out_key, derivation, output_index,derived_key);
}
crypto::public_key device_default::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
@@ -236,7 +237,7 @@ namespace hw {
}
bool device_default::generate_key_derivation(const crypto::public_key &key1, const crypto::secret_key &key2, crypto::key_derivation &derivation) {
- return crypto::generate_key_derivation(key1, key2, derivation);
+ return crypto::wallet::generate_key_derivation(key1, key2, derivation);
}
bool device_default::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res){
diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp
index 64cad78b0..bdd99f89c 100644
--- a/src/device/device_default.hpp
+++ b/src/device/device_default.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/device_io.hpp b/src/device/device_io.hpp
index fe66736f7..6a7744c11 100644
--- a/src/device/device_io.hpp
+++ b/src/device/device_io.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/device_io_hid.cpp b/src/device/device_io_hid.cpp
index 840529c38..7c61c3b1a 100644
--- a/src/device/device_io_hid.cpp
+++ b/src/device/device_io_hid.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/device_io_hid.hpp b/src/device/device_io_hid.hpp
index 96cb8d993..e6d76f276 100644
--- a/src/device/device_io_hid.hpp
+++ b/src/device/device_io_hid.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index 222a84d3f..4bd3d75b1 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -1108,7 +1108,7 @@ namespace hw {
for(size_t n=0; n < additional_derivations.size();++n) {
if(derivation == additional_derivations[n]) {
pkey = &additional_tx_pub_keys[n];
- MDEBUG("conceal derivation with additionnal tx pub key");
+ MDEBUG("conceal derivation with additional tx pub key");
break;
}
}
@@ -1468,8 +1468,8 @@ namespace hw {
offset = set_command_header(INS_PREFIX_HASH,2,cnt);
len = pref_length - pref_offset;
//options
- if (len > (BUFFER_SEND_SIZE-7)) {
- len = BUFFER_SEND_SIZE-7;
+ if (len > (BUFFER_SEND_SIZE-offset-3)) {
+ len = BUFFER_SEND_SIZE-offset-3;
this->buffer_send[offset] = 0x80;
} else {
this->buffer_send[offset] = 0x00;
@@ -1640,20 +1640,20 @@ namespace hw {
//if (tx_version > 1)
{
- ASSERT_X(recv_len>=32, "Not enought data from device");
+ ASSERT_X(recv_len>=32, "Not enough data from device");
crypto::secret_key scalar1;
this->receive_secret((unsigned char*)scalar1.data, offset);
amount_keys.push_back(rct::sk2rct(scalar1));
recv_len -= 32;
}
- ASSERT_X(recv_len>=32, "Not enought data from device");
+ ASSERT_X(recv_len>=32, "Not enough data from device");
memmove(out_eph_public_key.data, &this->buffer_recv[offset], 32);
recv_len -= 32;
offset += 32;
if (need_additional_txkeys)
{
- ASSERT_X(recv_len>=32, "Not enought data from device");
+ ASSERT_X(recv_len>=32, "Not enough data from device");
memmove(additional_txkey.pub.data, &this->buffer_recv[offset], 32);
additional_tx_public_keys.push_back(additional_txkey.pub);
offset += 32;
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index 070162cbc..4036035c8 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/log.cpp b/src/device/log.cpp
index 616ad8e90..6e62f1dee 100644
--- a/src/device/log.cpp
+++ b/src/device/log.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device/log.hpp b/src/device/log.hpp
index bfe6e9edc..66c3e06db 100644
--- a/src/device/log.hpp
+++ b/src/device/log.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/CMakeLists.txt b/src/device_trezor/CMakeLists.txt
index 250939da7..f105f68b7 100644
--- a/src/device_trezor/CMakeLists.txt
+++ b/src/device_trezor/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/device_trezor/device_trezor.cpp b/src/device_trezor/device_trezor.cpp
index 8bde1cb75..7c3e8785d 100644
--- a/src/device_trezor/device_trezor.cpp
+++ b/src/device_trezor/device_trezor.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -678,8 +678,10 @@ namespace trezor {
throw exc::TrezorException("Trezor firmware 2.0.10 and lower are not supported. Please update.");
}
- // default client version, higher versions check will be added
unsigned client_version = 1;
+ if (trezor_version >= pack_version(2, 3, 1)){
+ client_version = 3;
+ }
#ifdef WITH_TREZOR_DEBUGGING
// Override client version for tests
diff --git a/src/device_trezor/device_trezor.hpp b/src/device_trezor/device_trezor.hpp
index f558b7b19..d91d1de3f 100644
--- a/src/device_trezor/device_trezor.hpp
+++ b/src/device_trezor/device_trezor.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/device_trezor_base.cpp b/src/device_trezor/device_trezor_base.cpp
index 354ae6691..f59be1573 100644
--- a/src/device_trezor/device_trezor_base.cpp
+++ b/src/device_trezor/device_trezor_base.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/device_trezor_base.hpp b/src/device_trezor/device_trezor_base.hpp
index 62b2c2bf4..4db8f0c8e 100644
--- a/src/device_trezor/device_trezor_base.hpp
+++ b/src/device_trezor/device_trezor_base.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor.hpp b/src/device_trezor/trezor.hpp
index 396a27534..b3f85f6a8 100644
--- a/src/device_trezor/trezor.hpp
+++ b/src/device_trezor/trezor.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor/exceptions.hpp b/src/device_trezor/trezor/exceptions.hpp
index 41e8c2875..9d63329e4 100644
--- a/src/device_trezor/trezor/exceptions.hpp
+++ b/src/device_trezor/trezor/exceptions.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor/messages_map.cpp b/src/device_trezor/trezor/messages_map.cpp
index 6956b369a..02869f760 100644
--- a/src/device_trezor/trezor/messages_map.cpp
+++ b/src/device_trezor/trezor/messages_map.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor/messages_map.hpp b/src/device_trezor/trezor/messages_map.hpp
index 28fe9f4c2..a903eaf92 100644
--- a/src/device_trezor/trezor/messages_map.hpp
+++ b/src/device_trezor/trezor/messages_map.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor/protocol.cpp b/src/device_trezor/trezor/protocol.cpp
index 2a7783497..25c3d816d 100644
--- a/src/device_trezor/trezor/protocol.cpp
+++ b/src/device_trezor/trezor/protocol.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor/protocol.hpp b/src/device_trezor/trezor/protocol.hpp
index 8fc5eba97..35e7d9605 100644
--- a/src/device_trezor/trezor/protocol.hpp
+++ b/src/device_trezor/trezor/protocol.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor/transport.cpp b/src/device_trezor/trezor/transport.cpp
index 52bee6c6c..a56090de0 100644
--- a/src/device_trezor/trezor/transport.cpp
+++ b/src/device_trezor/trezor/transport.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -32,6 +32,7 @@
#endif
#include <algorithm>
+#include <functional>
#include <boost/endian/conversion.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
@@ -711,7 +712,7 @@ namespace trezor{
// Start the asynchronous operation itself. The handle_receive function
// used as a callback will update the ec and length variables.
m_socket->async_receive_from(boost::asio::buffer(buffer), m_endpoint,
- boost::bind(&UdpTransport::handle_receive, _1, _2, &ec, &length));
+ std::bind(&UdpTransport::handle_receive, std::placeholders::_1, std::placeholders::_2, &ec, &length));
// Block until the asynchronous operation has completed.
do {
diff --git a/src/device_trezor/trezor/transport.hpp b/src/device_trezor/trezor/transport.hpp
index 9a43b3637..ff843f06b 100644
--- a/src/device_trezor/trezor/transport.hpp
+++ b/src/device_trezor/trezor/transport.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/device_trezor/trezor/trezor_defs.hpp b/src/device_trezor/trezor/trezor_defs.hpp
index f0697cdb5..9882d6d4b 100644
--- a/src/device_trezor/trezor/trezor_defs.hpp
+++ b/src/device_trezor/trezor/trezor_defs.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/gen_multisig/CMakeLists.txt b/src/gen_multisig/CMakeLists.txt
index 3a5e29273..6d8bdfb5c 100644
--- a/src/gen_multisig/CMakeLists.txt
+++ b/src/gen_multisig/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019, The Monero Project
+# Copyright (c) 2017-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/gen_multisig/gen_multisig.cpp b/src/gen_multisig/gen_multisig.cpp
index 06019c50e..15f7e5c0a 100644
--- a/src/gen_multisig/gen_multisig.cpp
+++ b/src/gen_multisig/gen_multisig.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/gen_ssl_cert/CMakeLists.txt b/src/gen_ssl_cert/CMakeLists.txt
index 471df021b..6203feb21 100644
--- a/src/gen_ssl_cert/CMakeLists.txt
+++ b/src/gen_ssl_cert/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019, The Monero Project
+# Copyright (c) 2017-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/gen_ssl_cert/gen_ssl_cert.cpp b/src/gen_ssl_cert/gen_ssl_cert.cpp
index 7a9b01700..1a048e9e8 100644
--- a/src/gen_ssl_cert/gen_ssl_cert.cpp
+++ b/src/gen_ssl_cert/gen_ssl_cert.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/hardforks/CMakeLists.txt b/src/hardforks/CMakeLists.txt
index bd2d14ceb..46f51e09d 100644
--- a/src/hardforks/CMakeLists.txt
+++ b/src/hardforks/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp
index 7ad09dbef..f4de0ddcf 100644
--- a/src/hardforks/hardforks.cpp
+++ b/src/hardforks/hardforks.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/hardforks/hardforks.h b/src/hardforks/hardforks.h
index e7bceca42..039f18176 100644
--- a/src/hardforks/hardforks.h
+++ b/src/hardforks/hardforks.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/CMakeLists.txt b/src/mnemonics/CMakeLists.txt
index acb9a4338..ed53a41f6 100644
--- a/src/mnemonics/CMakeLists.txt
+++ b/src/mnemonics/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/mnemonics/chinese_simplified.h b/src/mnemonics/chinese_simplified.h
index ff035dde0..7a211bc34 100644
--- a/src/mnemonics/chinese_simplified.h
+++ b/src/mnemonics/chinese_simplified.h
@@ -21,7 +21,7 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Code surrounding the word list is Copyright (c) 2014-2019, The Monero Project
+// Code surrounding the word list is Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/dutch.h b/src/mnemonics/dutch.h
index 14ba56a7e..29c346d42 100644
--- a/src/mnemonics/dutch.h
+++ b/src/mnemonics/dutch.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/electrum-words.cpp b/src/mnemonics/electrum-words.cpp
index 2dd40cc9a..bda18d950 100644
--- a/src/mnemonics/electrum-words.cpp
+++ b/src/mnemonics/electrum-words.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/electrum-words.h b/src/mnemonics/electrum-words.h
index 9aa727e45..8d4c5be66 100644
--- a/src/mnemonics/electrum-words.h
+++ b/src/mnemonics/electrum-words.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/english.h b/src/mnemonics/english.h
index 677b70052..b7eb3d643 100644
--- a/src/mnemonics/english.h
+++ b/src/mnemonics/english.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/english_old.h b/src/mnemonics/english_old.h
index 179fc45ec..f408b2a6c 100644
--- a/src/mnemonics/english_old.h
+++ b/src/mnemonics/english_old.h
@@ -1,6 +1,6 @@
// Word list originally created as part of the Electrum project, Copyright (C) 2014 Thomas Voegtlin
//
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/esperanto.h b/src/mnemonics/esperanto.h
index ef63a2235..4897fe0b3 100644
--- a/src/mnemonics/esperanto.h
+++ b/src/mnemonics/esperanto.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/french.h b/src/mnemonics/french.h
index 85925aa53..d5a7b6cb6 100644
--- a/src/mnemonics/french.h
+++ b/src/mnemonics/french.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/german.h b/src/mnemonics/german.h
index 40116970c..c38a1fb83 100644
--- a/src/mnemonics/german.h
+++ b/src/mnemonics/german.h
@@ -1,6 +1,6 @@
// Word list created by Monero contributor Shrikez
//
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/italian.h b/src/mnemonics/italian.h
index 204fdcb78..f202e23e2 100644
--- a/src/mnemonics/italian.h
+++ b/src/mnemonics/italian.h
@@ -1,6 +1,6 @@
// Word list created by Monero contributor Shrikez
//
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/japanese.h b/src/mnemonics/japanese.h
index 6213c4976..899d78f48 100644
--- a/src/mnemonics/japanese.h
+++ b/src/mnemonics/japanese.h
@@ -21,7 +21,7 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Code surrounding the word list is Copyright (c) 2014-2019, The Monero Project
+// Code surrounding the word list is Copyright (c) 2014-2020, The Monero Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
diff --git a/src/mnemonics/language_base.h b/src/mnemonics/language_base.h
index 7d2599e9a..bf8793aa2 100644
--- a/src/mnemonics/language_base.h
+++ b/src/mnemonics/language_base.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -41,6 +41,7 @@
#include <boost/algorithm/string.hpp>
#include "misc_log_ex.h"
#include "fnv1.h"
+#include "common/utf8.h"
/*!
* \namespace Language
@@ -73,78 +74,11 @@ namespace Language
return prefix;
}
- template<typename T>
- inline T utf8canonical(const T &s)
- {
- T sc = "";
- size_t avail = s.size();
- const char *ptr = s.data();
- wint_t cp = 0;
- int bytes = 1;
- char wbuf[8], *wptr;
- while (avail--)
- {
- if ((*ptr & 0x80) == 0)
- {
- cp = *ptr++;
- bytes = 1;
- }
- else if ((*ptr & 0xe0) == 0xc0)
- {
- if (avail < 1)
- throw std::runtime_error("Invalid UTF-8");
- cp = (*ptr++ & 0x1f) << 6;
- cp |= *ptr++ & 0x3f;
- --avail;
- bytes = 2;
- }
- else if ((*ptr & 0xf0) == 0xe0)
- {
- if (avail < 2)
- throw std::runtime_error("Invalid UTF-8");
- cp = (*ptr++ & 0xf) << 12;
- cp |= (*ptr++ & 0x3f) << 6;
- cp |= *ptr++ & 0x3f;
- avail -= 2;
- bytes = 3;
- }
- else if ((*ptr & 0xf8) == 0xf0)
- {
- if (avail < 3)
- throw std::runtime_error("Invalid UTF-8");
- cp = (*ptr++ & 0x7) << 18;
- cp |= (*ptr++ & 0x3f) << 12;
- cp |= (*ptr++ & 0x3f) << 6;
- cp |= *ptr++ & 0x3f;
- avail -= 3;
- bytes = 4;
- }
- else
- throw std::runtime_error("Invalid UTF-8");
-
- cp = std::towlower(cp);
- wptr = wbuf;
- switch (bytes)
- {
- case 1: *wptr++ = cp; break;
- case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
- case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
- case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
- default: throw std::runtime_error("Invalid UTF-8");
- }
- *wptr = 0;
- sc += T(wbuf, bytes);
- cp = 0;
- bytes = 1;
- }
- return sc;
- }
-
struct WordHash
{
std::size_t operator()(const epee::wipeable_string &s) const
{
- const epee::wipeable_string sc = utf8canonical(s);
+ const epee::wipeable_string sc = tools::utf8canonical(s, [](wint_t c) -> wint_t { return std::towlower(c); });
return epee::fnv::FNV1a(sc.data(), sc.size());
}
};
@@ -153,8 +87,8 @@ namespace Language
{
bool operator()(const epee::wipeable_string &s0, const epee::wipeable_string &s1) const
{
- const epee::wipeable_string s0c = utf8canonical(s0);
- const epee::wipeable_string s1c = utf8canonical(s1);
+ const epee::wipeable_string s0c = tools::utf8canonical(s0, [](wint_t c) -> wint_t { return std::towlower(c); });
+ const epee::wipeable_string s1c = tools::utf8canonical(s1, [](wint_t c) -> wint_t { return std::towlower(c); });
return s0c == s1c;
}
};
diff --git a/src/mnemonics/lojban.h b/src/mnemonics/lojban.h
index b6baf46c4..95d8b4633 100644
--- a/src/mnemonics/lojban.h
+++ b/src/mnemonics/lojban.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/portuguese.h b/src/mnemonics/portuguese.h
index dbc51fb2a..090278f27 100644
--- a/src/mnemonics/portuguese.h
+++ b/src/mnemonics/portuguese.h
@@ -21,7 +21,7 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Code surrounding the word list is Copyright (c) 2014-2019, The Monero Project
+// Code surrounding the word list is Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/russian.h b/src/mnemonics/russian.h
index d36942a9b..ca2629c1a 100644
--- a/src/mnemonics/russian.h
+++ b/src/mnemonics/russian.h
@@ -1,6 +1,6 @@
// Word list created by Monero contributor sammy007
//
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/singleton.h b/src/mnemonics/singleton.h
index ffe3fe4de..10d220b65 100644
--- a/src/mnemonics/singleton.h
+++ b/src/mnemonics/singleton.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/mnemonics/spanish.h b/src/mnemonics/spanish.h
index a05485775..f3adaaf42 100644
--- a/src/mnemonics/spanish.h
+++ b/src/mnemonics/spanish.h
@@ -21,7 +21,7 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Code surrounding the word list is Copyright (c) 2014-2019, The Monero Project
+// Code surrounding the word list is Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/multisig/CMakeLists.txt b/src/multisig/CMakeLists.txt
index 4631b75ef..eaa2c6f71 100644
--- a/src/multisig/CMakeLists.txt
+++ b/src/multisig/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019, The Monero Project
+# Copyright (c) 2017-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp
index 999894db0..272de73b2 100644
--- a/src/multisig/multisig.cpp
+++ b/src/multisig/multisig.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -82,6 +82,7 @@ namespace cryptonote
{
rct::key sk = rct::scalarmultKey(rct::pk2rct(k), rct::sk2rct(blinded_skey));
crypto::secret_key msk = get_multisig_blinded_secret_key(rct::rct2sk(sk));
+ memwipe(&sk, sizeof(sk));
multisig_keys.push_back(msk);
sc_add(spend_skey.bytes, spend_skey.bytes, (const unsigned char*)msk.data);
}
@@ -126,10 +127,10 @@ namespace cryptonote
//-----------------------------------------------------------------
crypto::secret_key generate_multisig_view_secret_key(const crypto::secret_key &skey, const std::vector<crypto::secret_key> &skeys)
{
- rct::key view_skey = rct::sk2rct(get_multisig_blinded_secret_key(skey));
+ crypto::secret_key view_skey = get_multisig_blinded_secret_key(skey);
for (const auto &k: skeys)
- sc_add(view_skey.bytes, view_skey.bytes, rct::sk2rct(k).bytes);
- return rct::rct2sk(view_skey);
+ sc_add((unsigned char*)&view_skey, rct::sk2rct(view_skey).bytes, rct::sk2rct(k).bytes);
+ return view_skey;
}
//-----------------------------------------------------------------
crypto::public_key generate_multisig_M_N_spend_public_key(const std::vector<crypto::public_key> &pkeys)
diff --git a/src/multisig/multisig.h b/src/multisig/multisig.h
index bc6edbb05..eab32187c 100644
--- a/src/multisig/multisig.h
+++ b/src/multisig/multisig.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/dandelionpp.cpp b/src/net/dandelionpp.cpp
index 4d2f75428..e0d2821e5 100644
--- a/src/net/dandelionpp.cpp
+++ b/src/net/dandelionpp.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/dandelionpp.h b/src/net/dandelionpp.h
index 75b63bc0c..345f868af 100644
--- a/src/net/dandelionpp.h
+++ b/src/net/dandelionpp.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/i2p_address.cpp b/src/net/i2p_address.cpp
index f4cc75fee..6c03b3808 100644
--- a/src/net/i2p_address.cpp
+++ b/src/net/i2p_address.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/i2p_address.h b/src/net/i2p_address.h
index 28a1118ba..5a694419d 100644
--- a/src/net/i2p_address.h
+++ b/src/net/i2p_address.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/socks.cpp b/src/net/socks.cpp
index 5a27e16f4..3463f452c 100644
--- a/src/net/socks.cpp
+++ b/src/net/socks.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/socks.h b/src/net/socks.h
index 4d1d34e9e..739c972ab 100644
--- a/src/net/socks.h
+++ b/src/net/socks.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/socks_connect.cpp b/src/net/socks_connect.cpp
index a5557f6f8..9db9d4483 100644
--- a/src/net/socks_connect.cpp
+++ b/src/net/socks_connect.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/socks_connect.h b/src/net/socks_connect.h
index 44b0fa2b3..45bb10efe 100644
--- a/src/net/socks_connect.h
+++ b/src/net/socks_connect.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/net/zmq.cpp b/src/net/zmq.cpp
index 7ea80b907..15560ca7e 100644
--- a/src/net/zmq.cpp
+++ b/src/net/zmq.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -158,20 +158,6 @@ namespace zmq
return unsigned(max_out) < added ? max_out : int(added);
}
};
-
- template<typename F, typename... T>
- expect<void> retry_op(F op, T&&... args) noexcept(noexcept(op(args...)))
- {
- for (;;)
- {
- if (0 <= op(args...))
- return success();
-
- const int error = zmq_errno();
- if (error != EINTR)
- return make_error_code(error);
- }
- }
} // anonymous
expect<std::string> receive(void* const socket, const int flags)
diff --git a/src/net/zmq.h b/src/net/zmq.h
index 65560b62e..fa4ef2fc9 100644
--- a/src/net/zmq.h
+++ b/src/net/zmq.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -26,6 +26,8 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#pragma once
+
#include <memory>
#include <string>
#include <system_error>
@@ -105,6 +107,26 @@ namespace zmq
//! Unique ZMQ socket handle, calls `zmq_close` on destruction.
using socket = std::unique_ptr<void, close>;
+ /*! Retry a ZMQ function on `EINTR` errors. `F` must return an int with
+ values less than 0 on error.
+
+ \param op The ZMQ function to execute + retry
+ \param args Forwarded to `op`. Must be resuable in case of retry.
+ \return All errors except for `EINTR`. */
+ template<typename F, typename... T>
+ expect<void> retry_op(F op, T&&... args) noexcept(noexcept(op(args...)))
+ {
+ for (;;)
+ {
+ if (0 <= op(args...))
+ return success();
+
+ const int error = zmq_errno();
+ if (error != EINTR)
+ return make_error_code(error);
+ }
+ }
+
/*! Read all parts of the next message on `socket`. Blocks until the entire
next message (all parts) are read, or until `zmq_term` is called on the
`zmq_context` associated with `socket`. If the context is terminated,
diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt
index 3aecc3cf9..cfd8273b4 100644
--- a/src/p2p/CMakeLists.txt
+++ b/src/p2p/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp
index 58c5706de..1c5dca0d7 100644
--- a/src/p2p/net_node.cpp
+++ b/src/p2p/net_node.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 57b1335eb..e81371783 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 2d7600f7a..175741146 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -31,7 +31,7 @@
// IP blocking adapted from Boolberry
#include <algorithm>
-#include <boost/bind.hpp>
+#include <boost/bind/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional/optional.hpp>
@@ -604,16 +604,12 @@ namespace nodetool
if (nettype == cryptonote::TESTNET)
{
full_addrs.insert("212.83.175.67:28080");
- full_addrs.insert("5.9.100.248:28080");
- full_addrs.insert("163.172.182.165:28080");
- full_addrs.insert("195.154.123.123:28080");
full_addrs.insert("212.83.172.165:28080");
full_addrs.insert("192.110.160.146:28080");
}
else if (nettype == cryptonote::STAGENET)
{
full_addrs.insert("162.210.173.150:38080");
- full_addrs.insert("162.210.173.151:38080");
full_addrs.insert("192.110.160.146:38080");
}
else if (nettype == cryptonote::FAKECHAIN)
@@ -621,17 +617,14 @@ namespace nodetool
}
else
{
- full_addrs.insert("107.152.130.98:18080");
full_addrs.insert("212.83.175.67:18080");
- full_addrs.insert("5.9.100.248:18080");
- full_addrs.insert("163.172.182.165:18080");
- full_addrs.insert("161.67.132.39:18080");
- full_addrs.insert("198.74.231.92:18080");
- full_addrs.insert("195.154.123.123:18080");
full_addrs.insert("212.83.172.165:18080");
full_addrs.insert("192.110.160.146:18080");
full_addrs.insert("88.198.163.90:18080");
full_addrs.insert("95.217.25.101:18080");
+ full_addrs.insert("209.250.243.248:18080");
+ full_addrs.insert("104.238.221.81:18080");
+ full_addrs.insert("66.85.74.134:18080");
}
return full_addrs;
}
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 6a6100e0c..393d38e0a 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index 300181bbb..992462d0b 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h
index bd5063510..37a85d526 100644
--- a/src/p2p/net_peerlist_boost_serialization.h
+++ b/src/p2p/net_peerlist_boost_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index 609661871..bbc165cfa 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/p2p/stdafx.h b/src/p2p/stdafx.h
index 12a371702..a689b1c15 100644
--- a/src/p2p/stdafx.h
+++ b/src/p2p/stdafx.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/platform/mingw/alloca.h b/src/platform/mingw/alloca.h
index e4722af2a..b514051aa 100644
--- a/src/platform/mingw/alloca.h
+++ b/src/platform/mingw/alloca.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/platform/msc/alloca.h b/src/platform/msc/alloca.h
index fcf1731b0..a9ca8cc84 100644
--- a/src/platform/msc/alloca.h
+++ b/src/platform/msc/alloca.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/platform/msc/inline_c.h b/src/platform/msc/inline_c.h
index 23c11bd06..2a4952cff 100644
--- a/src/platform/msc/inline_c.h
+++ b/src/platform/msc/inline_c.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/platform/msc/stdbool.h b/src/platform/msc/stdbool.h
index 4d24995bd..445b625b4 100644
--- a/src/platform/msc/stdbool.h
+++ b/src/platform/msc/stdbool.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/platform/msc/sys/param.h b/src/platform/msc/sys/param.h
index e3cfb7e86..e5d208003 100644
--- a/src/platform/msc/sys/param.h
+++ b/src/platform/msc/sys/param.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/ringct/CMakeLists.txt b/src/ringct/CMakeLists.txt
index 0192aa931..40b2dfd55 100644
--- a/src/ringct/CMakeLists.txt
+++ b/src/ringct/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2016-2019, The Monero Project
+# Copyright (c) 2016-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index 6b88fd730..359dfa879 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/ringct/bulletproofs.h b/src/ringct/bulletproofs.h
index 21d494834..d8a9fa4ff 100644
--- a/src/ringct/bulletproofs.h
+++ b/src/ringct/bulletproofs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/ringct/rctCryptoOps.c b/src/ringct/rctCryptoOps.c
index fbbf6f9bd..506f85c16 100644
--- a/src/ringct/rctCryptoOps.c
+++ b/src/ringct/rctCryptoOps.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/ringct/rctCryptoOps.h b/src/ringct/rctCryptoOps.h
index 2a25d13a7..dabb2606a 100644
--- a/src/ringct/rctCryptoOps.h
+++ b/src/ringct/rctCryptoOps.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index a7b265d63..2e3e7007e 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -29,6 +29,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "misc_log_ex.h"
+#include "misc_language.h"
#include "common/perf_timer.h"
#include "common/threadpool.h"
#include "common/util.h"
@@ -108,6 +109,7 @@ namespace rct {
//Borromean (c.f. gmax/andytoshi's paper)
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
key64 L[2], alpha;
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(alpha, sizeof(alpha));});
key c;
int naught = 0, prime = 0, ii = 0, jj=0;
boroSig bb;
@@ -190,6 +192,7 @@ namespace rct {
vector<geDsmp> Ip(dsRows);
rv.II = keyV(dsRows);
keyV alpha(rows);
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(alpha.data(), alpha.size() * sizeof(alpha[0]));});
keyV aG(rows);
rv.ss = keyM(cols, aG);
keyV aHP(dsRows);
@@ -548,7 +551,7 @@ namespace rct {
subKeys(M[i][1], pubs[i].mask, Cout);
}
mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
- memwipe(&sk[0], sizeof(key));
+ memwipe(sk.data(), sk.size() * sizeof(key));
return result;
}
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index bf4b7b4aa..9b7f26a02 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -48,6 +48,7 @@ extern "C" {
#include "hex.h"
#include "span.h"
+#include "memwipe.h"
#include "serialization/vector.h"
#include "serialization/debug_archive.h"
#include "serialization/binary_archive.h"
@@ -106,6 +107,8 @@ namespace rct {
key L;
key R;
key ki;
+
+ ~multisig_kLRki() { memwipe(&k, sizeof(k)); }
};
struct multisig_out {
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index fe5e5a85b..19298c969 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -45,8 +45,11 @@ set(daemon_messages_sources
message.cpp
daemon_messages.cpp)
+set(rpc_pub_sources zmq_pub.cpp)
+
set(daemon_rpc_server_sources
daemon_handler.cpp
+ zmq_pub.cpp
zmq_server.cpp)
@@ -59,8 +62,9 @@ set(rpc_headers
rpc_version_str.h
rpc_handler.h)
-set(daemon_rpc_server_headers)
+set(rpc_pub_headers zmq_pub.h)
+set(daemon_rpc_server_headers)
set(rpc_daemon_private_headers
bootstrap_daemon.h
@@ -83,6 +87,8 @@ set(daemon_rpc_server_private_headers
monero_private_headers(rpc
${rpc_private_headers})
+set(rpc_pub_private_headers)
+
monero_private_headers(daemon_rpc_server
${daemon_rpc_server_private_headers})
@@ -97,6 +103,11 @@ monero_add_library(rpc
${rpc_headers}
${rpc_private_headers})
+monero_add_library(rpc_pub
+ ${rpc_pub_sources}
+ ${rpc_pub_headers}
+ ${rpc_pub_private_headers})
+
monero_add_library(daemon_messages
${daemon_messages_sources}
${daemon_messages_headers}
@@ -131,6 +142,14 @@ target_link_libraries(rpc
PRIVATE
${EXTRA_LIBRARIES})
+target_link_libraries(rpc_pub
+ PUBLIC
+ epee
+ net
+ cryptonote_basic
+ serialization
+ ${Boost_THREAD_LIBRARY})
+
target_link_libraries(daemon_messages
LINK_PRIVATE
cryptonote_core
@@ -142,6 +161,7 @@ target_link_libraries(daemon_messages
target_link_libraries(daemon_rpc_server
LINK_PRIVATE
rpc
+ rpc_pub
cryptonote_core
cryptonote_protocol
version
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index a789a7a1a..bc561abc4 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -68,6 +68,11 @@ using namespace epee;
#define DEFAULT_PAYMENT_DIFFICULTY 1000
#define DEFAULT_PAYMENT_CREDITS_PER_HASH 100
+#define RESTRICTED_BLOCK_HEADER_RANGE 1000
+#define RESTRICTED_TRANSACTIONS_COUNT 100
+#define RESTRICTED_SPENT_KEY_IMAGES_COUNT 5000
+#define RESTRICTED_BLOCK_COUNT 1000
+
#define RPC_TRACKER(rpc) \
PERF_TIMER(rpc); \
RPCTracker tracker(#rpc, PERF_TIMER_NAME(rpc))
@@ -265,25 +270,25 @@ namespace cryptonote
{
if (!m_restricted && nettype() != FAKECHAIN)
{
- MERROR("RPC payment enabled, but server is not restricted, anyone can adjust their balance to bypass payment");
+ MFATAL("RPC payment enabled, but server is not restricted, anyone can adjust their balance to bypass payment");
return false;
}
cryptonote::address_parse_info info;
if (!get_account_address_from_str(info, nettype(), address))
{
- MERROR("Invalid payment address: " << address);
+ MFATAL("Invalid payment address: " << address);
return false;
}
if (info.is_subaddress)
{
- MERROR("Payment address may not be a subaddress: " << address);
+ MFATAL("Payment address may not be a subaddress: " << address);
return false;
}
uint64_t diff = command_line::get_arg(vm, arg_rpc_payment_difficulty);
uint64_t credits = command_line::get_arg(vm, arg_rpc_payment_credits);
if (diff == 0 || credits == 0)
{
- MERROR("Payments difficulty and/or payments credits are 0, but a payment address was given");
+ MFATAL("Payments difficulty and/or payments credits are 0, but a payment address was given");
return false;
}
m_rpc_payment_allow_free_loopback = command_line::get_arg(vm, arg_rpc_payment_allow_free_loopback);
@@ -303,7 +308,7 @@ namespace cryptonote
if (!set_bootstrap_daemon(command_line::get_arg(vm, arg_bootstrap_daemon_address),
command_line::get_arg(vm, arg_bootstrap_daemon_login)))
{
- MERROR("Failed to parse bootstrap daemon address");
+ MFATAL("Failed to parse bootstrap daemon address");
return false;
}
@@ -639,6 +644,13 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
return r;
+ const bool restricted = m_restricted && ctx;
+ if (restricted && req.heights.size() > RESTRICTED_BLOCK_COUNT)
+ {
+ res.status = "Too many blocks requested in restricted mode";
+ return true;
+ }
+
res.status = "Failed";
res.blocks.clear();
res.blocks.reserve(req.heights.size());
@@ -793,11 +805,17 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
return ok;
- CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
-
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
+ if (restricted && req.txs_hashes.size() > RESTRICTED_TRANSACTIONS_COUNT)
+ {
+ res.status = "Too many transactions requested in restricted mode";
+ return true;
+ }
+
+ CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
+
std::vector<crypto::hash> vh;
for(const auto& tx_hex_str: req.txs_hashes)
{
@@ -1027,11 +1045,17 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
return ok;
- CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
-
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
+ if (restricted && req.key_images.size() > RESTRICTED_SPENT_KEY_IMAGES_COUNT)
+ {
+ res.status = "Too many key images queried in restricted mode";
+ return true;
+ }
+
+ CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
+
std::vector<crypto::key_image> key_images;
for(const auto& ki_hex_str: req.key_images)
{
@@ -1990,7 +2014,7 @@ namespace cryptonote
r = false;
}
res.untrusted = true;
- return true;
+ return r;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
@@ -2034,6 +2058,14 @@ namespace cryptonote
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
+ const bool restricted = m_restricted && ctx;
+ if (restricted && req.hashes.size() > RESTRICTED_BLOCK_COUNT)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_RESTRICTED;
+ error_resp.message = "Too many block headers requested in restricted mode";
+ return false;
+ }
+
auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool {
crypto::hash block_hash;
bool hash_parsed = parse_hash256(hash, block_hash);
@@ -2069,7 +2101,6 @@ namespace cryptonote
return true;
};
- const bool restricted = m_restricted && ctx;
if (!req.hash.empty())
{
if (!get(req.hash, req.fill_pow_hash, res.block_header, restricted, error_resp))
@@ -2101,6 +2132,14 @@ namespace cryptonote
error_resp.message = "Invalid start/end heights.";
return false;
}
+ const bool restricted = m_restricted && ctx;
+ if (restricted && req.end_height - req.start_height > RESTRICTED_BLOCK_HEADER_RANGE)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_RESTRICTED;
+ error_resp.message = "Too many block headers requested.";
+ return false;
+ }
+
CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false);
for (uint64_t h = req.start_height; h <= req.end_height; ++h)
{
@@ -2127,7 +2166,6 @@ namespace cryptonote
return false;
}
res.headers.push_back(block_header_response());
- const bool restricted = m_restricted && ctx;
bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.headers.back(), req.fill_pow_hash && !restricted);
if (!response_filled)
{
@@ -2778,7 +2816,7 @@ namespace cryptonote
crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
cryptonote::blobdata txblob;
- if (!m_core.get_pool_transaction(txid, txblob, relay_category::legacy))
+ if (m_core.get_pool_transaction(txid, txblob, relay_category::legacy))
{
NOTIFY_NEW_TRANSACTIONS::request r;
r.txs.push_back(std::move(txblob));
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 3c404bbd8..dcf6b4e4b 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index a3c187c24..09cd67d7d 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h
index 2fd42f43f..1458049ab 100644
--- a/src/rpc/core_rpc_server_error_codes.h
+++ b/src/rpc/core_rpc_server_error_codes.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -48,6 +48,7 @@
#define CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW -16
#define CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT -17
#define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18
+#define CORE_RPC_ERROR_CODE_RESTRICTED -19
static inline const char *get_rpc_server_error_message(int64_t code)
{
@@ -70,6 +71,7 @@ static inline const char *get_rpc_server_error_message(int64_t code)
case CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW: return "Payment too low";
case CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT: return "Duplicate payment";
case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment";
+ case CORE_RPC_ERROR_CODE_RESTRICTED: return "Parameters beyond restricted allowance";
default: MERROR("Unknown error: " << code); return "Unknown error";
}
}
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index de0510fec..ab28319cb 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -101,7 +101,8 @@ namespace rpc
{u8"key_images_spent", handle_message<KeyImagesSpent>},
{u8"mining_status", handle_message<MiningStatus>},
{u8"save_bc", handle_message<SaveBC>},
- {u8"send_raw_tx", handle_message<SendRawTxHex>},
+ {u8"send_raw_tx", handle_message<SendRawTx>},
+ {u8"send_raw_tx_hex", handle_message<SendRawTxHex>},
{u8"set_log_level", handle_message<SetLogLevel>},
{u8"start_mining", handle_message<StartMining>},
{u8"stop_mining", handle_message<StopMining>}
diff --git a/src/rpc/daemon_handler.h b/src/rpc/daemon_handler.h
index b797b1155..aa3470c25 100644
--- a/src/rpc/daemon_handler.h
+++ b/src/rpc/daemon_handler.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/daemon_messages.cpp b/src/rpc/daemon_messages.cpp
index 5c179408e..887486f77 100644
--- a/src/rpc/daemon_messages.cpp
+++ b/src/rpc/daemon_messages.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,14 +34,14 @@ namespace cryptonote
namespace rpc
{
-void GetHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHeight::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetHeight::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, height, height);
}
@@ -52,7 +52,7 @@ void GetHeight::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlocksFast::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlocksFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, block_ids, block_ids);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -66,7 +66,7 @@ void GetBlocksFast::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, prune, prune);
}
-void GetBlocksFast::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlocksFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, blocks, blocks);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -83,7 +83,7 @@ void GetBlocksFast::Response::fromJson(const rapidjson::Value& val)
}
-void GetHashesFast::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHashesFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, known_hashes, known_hashes);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -95,7 +95,7 @@ void GetHashesFast::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, start_height, start_height);
}
-void GetHashesFast::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetHashesFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, hashes, hashes);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
@@ -110,7 +110,7 @@ void GetHashesFast::Response::fromJson(const rapidjson::Value& val)
}
-void GetTransactions::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactions::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx_hashes, tx_hashes);
}
@@ -120,7 +120,7 @@ void GetTransactions::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, tx_hashes, tx_hashes);
}
-void GetTransactions::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactions::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, txs, txs);
INSERT_INTO_JSON_OBJECT(dest, missed_hashes, missed_hashes);
@@ -133,7 +133,7 @@ void GetTransactions::Response::fromJson(const rapidjson::Value& val)
}
-void KeyImagesSpent::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void KeyImagesSpent::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, key_images, key_images);
}
@@ -143,7 +143,7 @@ void KeyImagesSpent::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
-void KeyImagesSpent::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void KeyImagesSpent::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, spent_status, spent_status);
}
@@ -154,7 +154,7 @@ void KeyImagesSpent::Response::fromJson(const rapidjson::Value& val)
}
-void GetTxGlobalOutputIndices::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTxGlobalOutputIndices::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx_hash, tx_hash);
}
@@ -164,7 +164,7 @@ void GetTxGlobalOutputIndices::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, tx_hash, tx_hash);
}
-void GetTxGlobalOutputIndices::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTxGlobalOutputIndices::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, output_indices, output_indices);
}
@@ -174,7 +174,7 @@ void GetTxGlobalOutputIndices::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
}
-void SendRawTx::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SendRawTx::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx, tx);
INSERT_INTO_JSON_OBJECT(dest, relay, relay);
@@ -186,7 +186,7 @@ void SendRawTx::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, relay, relay);
}
-void SendRawTx::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SendRawTx::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, relayed, relayed);
}
@@ -197,7 +197,7 @@ void SendRawTx::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, relayed, relayed);
}
-void SendRawTxHex::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SendRawTxHex::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, tx_as_hex, tx_as_hex);
INSERT_INTO_JSON_OBJECT(dest, relay, relay);
@@ -209,7 +209,7 @@ void SendRawTxHex::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, relay, relay);
}
-void StartMining::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StartMining::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, miner_address, miner_address);
INSERT_INTO_JSON_OBJECT(dest, threads_count, threads_count);
@@ -225,7 +225,7 @@ void StartMining::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, ignore_battery, ignore_battery);
}
-void StartMining::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StartMining::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void StartMining::Response::fromJson(const rapidjson::Value& val)
@@ -233,14 +233,14 @@ void StartMining::Response::fromJson(const rapidjson::Value& val)
}
-void StopMining::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StopMining::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void StopMining::Request::fromJson(const rapidjson::Value& val)
{
}
-void StopMining::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void StopMining::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void StopMining::Response::fromJson(const rapidjson::Value& val)
@@ -248,14 +248,14 @@ void StopMining::Response::fromJson(const rapidjson::Value& val)
}
-void MiningStatus::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void MiningStatus::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void MiningStatus::Request::fromJson(const rapidjson::Value& val)
{
}
-void MiningStatus::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void MiningStatus::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, active, active);
INSERT_INTO_JSON_OBJECT(dest, speed, speed);
@@ -274,14 +274,14 @@ void MiningStatus::Response::fromJson(const rapidjson::Value& val)
}
-void GetInfo::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetInfo::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetInfo::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetInfo::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, info, info);
}
@@ -292,14 +292,14 @@ void GetInfo::Response::fromJson(const rapidjson::Value& val)
}
-void SaveBC::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SaveBC::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void SaveBC::Request::fromJson(const rapidjson::Value& val)
{
}
-void SaveBC::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SaveBC::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void SaveBC::Response::fromJson(const rapidjson::Value& val)
@@ -307,7 +307,7 @@ void SaveBC::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHash::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHash::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, height, height);
}
@@ -317,7 +317,7 @@ void GetBlockHash::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, height, height);
}
-void GetBlockHash::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHash::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, hash, hash);
}
@@ -328,14 +328,14 @@ void GetBlockHash::Response::fromJson(const rapidjson::Value& val)
}
-void GetLastBlockHeader::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetLastBlockHeader::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetLastBlockHeader::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetLastBlockHeader::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetLastBlockHeader::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, header, header);
}
@@ -346,7 +346,7 @@ void GetLastBlockHeader::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHeaderByHash::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHash::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, hash, hash);
}
@@ -356,7 +356,7 @@ void GetBlockHeaderByHash::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, hash, hash);
}
-void GetBlockHeaderByHash::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHash::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, header, header);
}
@@ -367,7 +367,7 @@ void GetBlockHeaderByHash::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHeaderByHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHeight::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, height, height);
}
@@ -377,7 +377,7 @@ void GetBlockHeaderByHeight::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, height, height);
}
-void GetBlockHeaderByHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeaderByHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, header, header);
}
@@ -388,7 +388,7 @@ void GetBlockHeaderByHeight::Response::fromJson(const rapidjson::Value& val)
}
-void GetBlockHeadersByHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeadersByHeight::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, heights, heights);
}
@@ -398,7 +398,7 @@ void GetBlockHeadersByHeight::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, heights, heights);
}
-void GetBlockHeadersByHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetBlockHeadersByHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, headers, headers);
}
@@ -409,14 +409,14 @@ void GetBlockHeadersByHeight::Response::fromJson(const rapidjson::Value& val)
}
-void GetPeerList::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetPeerList::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetPeerList::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetPeerList::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetPeerList::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, white_list, white_list);
INSERT_INTO_JSON_OBJECT(dest, gray_list, gray_list);
@@ -429,7 +429,7 @@ void GetPeerList::Response::fromJson(const rapidjson::Value& val)
}
-void SetLogLevel::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SetLogLevel::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, level, level);
}
@@ -439,7 +439,7 @@ void SetLogLevel::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, level, level);
}
-void SetLogLevel::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void SetLogLevel::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void SetLogLevel::Response::fromJson(const rapidjson::Value& val)
@@ -447,14 +447,14 @@ void SetLogLevel::Response::fromJson(const rapidjson::Value& val)
}
-void GetTransactionPool::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactionPool::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetTransactionPool::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetTransactionPool::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetTransactionPool::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, transactions, transactions);
INSERT_INTO_JSON_OBJECT(dest, key_images, key_images);
@@ -467,7 +467,7 @@ void GetTransactionPool::Response::fromJson(const rapidjson::Value& val)
}
-void HardForkInfo::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void HardForkInfo::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, version, version);
}
@@ -477,7 +477,7 @@ void HardForkInfo::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, version, version);
}
-void HardForkInfo::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void HardForkInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, info, info);
}
@@ -488,7 +488,7 @@ void HardForkInfo::Response::fromJson(const rapidjson::Value& val)
}
-void GetOutputHistogram::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputHistogram::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, amounts, amounts);
INSERT_INTO_JSON_OBJECT(dest, min_count, min_count);
@@ -506,7 +506,7 @@ void GetOutputHistogram::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, recent_cutoff, recent_cutoff);
}
-void GetOutputHistogram::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputHistogram::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, histogram, histogram);
}
@@ -517,7 +517,7 @@ void GetOutputHistogram::Response::fromJson(const rapidjson::Value& val)
}
-void GetOutputKeys::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputKeys::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, outputs, outputs);
}
@@ -527,7 +527,7 @@ void GetOutputKeys::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, outputs, outputs);
}
-void GetOutputKeys::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputKeys::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, keys, keys);
}
@@ -538,14 +538,14 @@ void GetOutputKeys::Response::fromJson(const rapidjson::Value& val)
}
-void GetRPCVersion::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetRPCVersion::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
void GetRPCVersion::Request::fromJson(const rapidjson::Value& val)
{
}
-void GetRPCVersion::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetRPCVersion::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, version, version);
}
@@ -555,7 +555,7 @@ void GetRPCVersion::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, version, version);
}
-void GetFeeEstimate::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetFeeEstimate::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, num_grace_blocks, num_grace_blocks);
}
@@ -565,7 +565,7 @@ void GetFeeEstimate::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
}
-void GetFeeEstimate::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetFeeEstimate::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, estimated_base_fee, estimated_base_fee);
INSERT_INTO_JSON_OBJECT(dest, fee_mask, fee_mask);
@@ -581,7 +581,7 @@ void GetFeeEstimate::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, hard_fork_version, hard_fork_version);
}
-void GetOutputDistribution::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputDistribution::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, amounts, amounts);
INSERT_INTO_JSON_OBJECT(dest, from_height, from_height);
@@ -597,7 +597,7 @@ void GetOutputDistribution::Request::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, cumulative, cumulative);
}
-void GetOutputDistribution::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void GetOutputDistribution::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, status, status);
INSERT_INTO_JSON_OBJECT(dest, distributions, distributions);
diff --git a/src/rpc/daemon_messages.h b/src/rpc/daemon_messages.h
index bb5059cdc..dea37c9a6 100644
--- a/src/rpc/daemon_messages.h
+++ b/src/rpc/daemon_messages.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
@@ -28,11 +28,11 @@
#pragma once
-#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <unordered_map>
#include <vector>
+#include "byte_stream.h"
#include "message.h"
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
#include "rpc/message_data_structs.h"
@@ -50,7 +50,7 @@ class classname \
public: \
Request() { } \
~Request() { } \
- void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const override final; \
+ void doToJson(rapidjson::Writer<epee::byte_stream>& dest) const override final; \
void fromJson(const rapidjson::Value& val) override final;
#define BEGIN_RPC_MESSAGE_RESPONSE \
@@ -59,7 +59,7 @@ class classname \
public: \
Response() { } \
~Response() { } \
- void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const override final; \
+ void doToJson(rapidjson::Writer<epee::byte_stream>& dest) const override final; \
void fromJson(const rapidjson::Value& val) override final;
#define END_RPC_MESSAGE_REQUEST };
diff --git a/src/rpc/daemon_rpc_version.h b/src/rpc/daemon_rpc_version.h
index b3eb9699b..d178a82bc 100644
--- a/src/rpc/daemon_rpc_version.h
+++ b/src/rpc/daemon_rpc_version.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/fwd.h b/src/rpc/fwd.h
new file mode 100644
index 000000000..72537f5a5
--- /dev/null
+++ b/src/rpc/fwd.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2019-2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+namespace cryptonote
+{
+ namespace listener
+ {
+ class zmq_pub;
+ }
+}
diff --git a/src/rpc/instanciations.cpp b/src/rpc/instanciations.cpp
index 94fdb5f18..ac992d4ad 100644
--- a/src/rpc/instanciations.cpp
+++ b/src/rpc/instanciations.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp
index 0d8983cb1..e4f17cef8 100644
--- a/src/rpc/message.cpp
+++ b/src/rpc/message.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
@@ -62,7 +62,7 @@ const rapidjson::Value& get_method_field(const rapidjson::Value& src)
}
}
-void Message::toJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+void Message::toJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, status, status);
@@ -151,9 +151,9 @@ cryptonote::rpc::error FullMessage::getError()
epee::byte_slice FullMessage::getRequest(const std::string& request, const Message& message, const unsigned id)
{
- rapidjson::StringBuffer buffer;
+ epee::byte_stream buffer;
{
- rapidjson::Writer<rapidjson::StringBuffer> dest{buffer};
+ rapidjson::Writer<epee::byte_stream> dest{buffer};
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, jsonrpc, (boost::string_ref{"2.0", 3}));
@@ -172,15 +172,15 @@ epee::byte_slice FullMessage::getRequest(const std::string& request, const Messa
if (!dest.IsComplete())
throw std::logic_error{"Invalid JSON tree generated"};
}
- return epee::byte_slice{{buffer.GetString(), buffer.GetSize()}};
+ return epee::byte_slice{std::move(buffer)};
}
epee::byte_slice FullMessage::getResponse(const Message& message, const rapidjson::Value& id)
{
- rapidjson::StringBuffer buffer;
+ epee::byte_stream buffer;
{
- rapidjson::Writer<rapidjson::StringBuffer> dest{buffer};
+ rapidjson::Writer<epee::byte_stream> dest{buffer};
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, jsonrpc, (boost::string_ref{"2.0", 3}));
@@ -207,7 +207,7 @@ epee::byte_slice FullMessage::getResponse(const Message& message, const rapidjso
if (!dest.IsComplete())
throw std::logic_error{"Invalid JSON tree generated"};
}
- return epee::byte_slice{{buffer.GetString(), buffer.GetSize()}};
+ return epee::byte_slice{std::move(buffer)};
}
// convenience functions for bad input
diff --git a/src/rpc/message.h b/src/rpc/message.h
index 8156e232c..b858a5913 100644
--- a/src/rpc/message.h
+++ b/src/rpc/message.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
@@ -29,11 +29,11 @@
#pragma once
#include <rapidjson/document.h>
-#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <string>
#include "byte_slice.h"
+#include "byte_stream.h"
#include "rpc/message_data_structs.h"
namespace cryptonote
@@ -44,7 +44,7 @@ namespace rpc
class Message
{
- virtual void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+ virtual void doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{}
public:
@@ -58,7 +58,7 @@ namespace rpc
virtual ~Message() { }
- void toJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const;
+ void toJson(rapidjson::Writer<epee::byte_stream>& dest) const;
virtual void fromJson(const rapidjson::Value& val);
diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h
index e64f5f163..085148d8a 100644
--- a/src/rpc/message_data_structs.h
+++ b/src/rpc/message_data_structs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp
index 9153e76ea..8601bd0b4 100644
--- a/src/rpc/rpc_args.cpp
+++ b/src/rpc/rpc_args.cpp
@@ -30,7 +30,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/asio/ip/address.hpp>
-#include <boost/bind.hpp>
+#include <functional>
#include "common/command_line.h"
#include "common/i18n.h"
#include "hex.h"
@@ -221,7 +221,7 @@ namespace cryptonote
std::vector<std::string> access_control_origins;
boost::split(access_control_origins, access_control_origins_input, boost::is_any_of(","));
- std::for_each(access_control_origins.begin(), access_control_origins.end(), boost::bind(&boost::trim<std::string>, _1, std::locale::classic()));
+ std::for_each(access_control_origins.begin(), access_control_origins.end(), std::bind(&boost::trim<std::string>, std::placeholders::_1, std::locale::classic()));
config.access_control_origins = std::move(access_control_origins);
}
diff --git a/src/rpc/rpc_args.h b/src/rpc/rpc_args.h
index ac6eb2744..4cf4279b2 100644
--- a/src/rpc/rpc_args.h
+++ b/src/rpc/rpc_args.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/rpc_handler.h b/src/rpc/rpc_handler.h
index 9a1c3fc12..97dd0598b 100644
--- a/src/rpc/rpc_handler.h
+++ b/src/rpc/rpc_handler.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/rpc_payment.cpp b/src/rpc/rpc_payment.cpp
index 2b9c19f57..edc8f0dda 100644
--- a/src/rpc/rpc_payment.cpp
+++ b/src/rpc/rpc_payment.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
@@ -92,6 +92,7 @@ namespace cryptonote
uint64_t rpc_payment::balance(const crypto::public_key &client, int64_t delta)
{
+ boost::lock_guard<boost::mutex> lock(mutex);
client_info &info = m_client_info[client]; // creates if not found
uint64_t credits = info.credits;
if (delta > 0 && credits > std::numeric_limits<uint64_t>::max() - delta)
@@ -107,6 +108,7 @@ namespace cryptonote
bool rpc_payment::pay(const crypto::public_key &client, uint64_t ts, uint64_t payment, const std::string &rpc, bool same_ts, uint64_t &credits)
{
+ boost::lock_guard<boost::mutex> lock(mutex);
client_info &info = m_client_info[client]; // creates if not found
if (ts < info.last_request_timestamp || (ts == info.last_request_timestamp && !same_ts))
{
@@ -130,6 +132,7 @@ namespace cryptonote
bool rpc_payment::get_info(const crypto::public_key &client, const std::function<bool(const cryptonote::blobdata&, cryptonote::block&, uint64_t &seed_height, crypto::hash &seed_hash)> &get_block_template, cryptonote::blobdata &hashing_blob, uint64_t &seed_height, crypto::hash &seed_hash, const crypto::hash &top, uint64_t &diff, uint64_t &credits_per_hash_found, uint64_t &credits, uint32_t &cookie)
{
+ boost::lock_guard<boost::mutex> lock(mutex);
client_info &info = m_client_info[client]; // creates if not found
const uint64_t now = time(NULL);
bool need_template = top != info.top || now >= info.block_template_update_time + STALE_THRESHOLD;
@@ -180,6 +183,7 @@ namespace cryptonote
bool rpc_payment::submit_nonce(const crypto::public_key &client, uint32_t nonce, const crypto::hash &top, int64_t &error_code, std::string &error_message, uint64_t &credits, crypto::hash &hash, cryptonote::block &block, uint32_t cookie, bool &stale)
{
+ boost::lock_guard<boost::mutex> lock(mutex);
client_info &info = m_client_info[client]; // creates if not found
if (cookie != info.cookie && cookie != info.cookie - 1)
{
@@ -272,6 +276,7 @@ namespace cryptonote
bool rpc_payment::foreach(const std::function<bool(const crypto::public_key &client, const client_info &info)> &f) const
{
+ boost::lock_guard<boost::mutex> lock(mutex);
for (std::unordered_map<crypto::public_key, client_info>::const_iterator i = m_client_info.begin(); i != m_client_info.end(); ++i)
{
if (!f(i->first, i->second))
@@ -283,8 +288,9 @@ namespace cryptonote
bool rpc_payment::load(std::string directory)
{
TRY_ENTRY();
+ boost::lock_guard<boost::mutex> lock(mutex);
m_directory = std::move(directory);
- std::string state_file_path = directory + "/" + RPC_PAYMENTS_DATA_FILENAME;
+ std::string state_file_path = m_directory + "/" + RPC_PAYMENTS_DATA_FILENAME;
MINFO("loading rpc payments data from " << state_file_path);
std::ifstream data;
data.open(state_file_path, std::ios_base::binary | std::ios_base::in);
@@ -313,6 +319,7 @@ namespace cryptonote
bool rpc_payment::store(const std::string &directory_) const
{
TRY_ENTRY();
+ boost::lock_guard<boost::mutex> lock(mutex);
const std::string &directory = directory_.empty() ? m_directory : directory_;
MDEBUG("storing rpc payments data to " << directory);
if (!tools::create_directories_if_necessary(directory))
@@ -345,6 +352,7 @@ namespace cryptonote
unsigned int rpc_payment::flush_by_age(time_t seconds)
{
+ boost::lock_guard<boost::mutex> lock(mutex);
unsigned int count = 0;
const time_t now = time(NULL);
time_t seconds0 = seconds;
@@ -358,7 +366,7 @@ namespace cryptonote
for (std::unordered_map<crypto::public_key, client_info>::iterator i = m_client_info.begin(); i != m_client_info.end(); )
{
std::unordered_map<crypto::public_key, client_info>::iterator j = i++;
- const time_t t = std::max(j->second.last_request_timestamp, j->second.update_time);
+ const time_t t = std::max(j->second.last_request_timestamp / 1000000, j->second.update_time);
const bool erase = t < ((j->second.credits == 0) ? threshold0 : threshold);
if (erase)
{
@@ -372,6 +380,7 @@ namespace cryptonote
uint64_t rpc_payment::get_hashes(unsigned int seconds) const
{
+ boost::lock_guard<boost::mutex> lock(mutex);
const uint64_t now = time(NULL);
uint64_t hashes = 0;
for (std::map<uint64_t, uint64_t>::const_reverse_iterator i = m_hashrate.crbegin(); i != m_hashrate.crend(); ++i)
@@ -385,6 +394,7 @@ namespace cryptonote
void rpc_payment::prune_hashrate(unsigned int seconds)
{
+ boost::lock_guard<boost::mutex> lock(mutex);
const uint64_t now = time(NULL);
std::map<uint64_t, uint64_t>::iterator i;
for (i = m_hashrate.begin(); i != m_hashrate.end(); ++i)
diff --git a/src/rpc/rpc_payment.h b/src/rpc/rpc_payment.h
index f6832fd34..dcd43f8d5 100644
--- a/src/rpc/rpc_payment.h
+++ b/src/rpc/rpc_payment.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
@@ -31,6 +31,7 @@
#include <string>
#include <unordered_set>
#include <unordered_map>
+#include <boost/thread/mutex.hpp>
#include <boost/serialization/version.hpp>
#include "cryptonote_basic/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"
@@ -139,6 +140,7 @@ namespace cryptonote
uint64_t m_nonces_stale;
uint64_t m_nonces_bad;
uint64_t m_nonces_dupe;
+ mutable boost::mutex mutex;
};
}
diff --git a/src/rpc/rpc_payment_costs.h b/src/rpc/rpc_payment_costs.h
index 3b27bf286..9bc0f8a2b 100644
--- a/src/rpc/rpc_payment_costs.h
+++ b/src/rpc/rpc_payment_costs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/rpc_payment_signature.cpp b/src/rpc/rpc_payment_signature.cpp
index 559f3a1e9..a5dc21717 100644
--- a/src/rpc/rpc_payment_signature.cpp
+++ b/src/rpc/rpc_payment_signature.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/rpc_payment_signature.h b/src/rpc/rpc_payment_signature.h
index 4a2fe2ea3..bf7ee061f 100644
--- a/src/rpc/rpc_payment_signature.h
+++ b/src/rpc/rpc_payment_signature.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/rpc_version_str.cpp b/src/rpc/rpc_version_str.cpp
index c60cf4891..b8b231c16 100644
--- a/src/rpc/rpc_version_str.cpp
+++ b/src/rpc/rpc_version_str.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/rpc_version_str.h b/src/rpc/rpc_version_str.h
index 930c807d2..b0cb47c5f 100644
--- a/src/rpc/rpc_version_str.h
+++ b/src/rpc/rpc_version_str.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/rpc/zmq_pub.cpp b/src/rpc/zmq_pub.cpp
new file mode 100644
index 000000000..0dffffac6
--- /dev/null
+++ b/src/rpc/zmq_pub.cpp
@@ -0,0 +1,478 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "zmq_pub.h"
+
+#include <algorithm>
+#include <boost/range/adaptor/filtered.hpp>
+#include <boost/range/adaptor/transformed.hpp>
+#include <boost/thread/locks.hpp>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <rapidjson/document.h>
+#include <rapidjson/stringbuffer.h>
+#include <rapidjson/writer.h>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include "common/expect.h"
+#include "crypto/crypto.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "cryptonote_basic/events.h"
+#include "misc_log_ex.h"
+#include "serialization/json_object.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.zmq"
+
+namespace
+{
+ constexpr const char txpool_signal[] = "tx_signal";
+
+ using chain_writer = void(epee::byte_stream&, std::uint64_t, epee::span<const cryptonote::block>);
+ using txpool_writer = void(epee::byte_stream&, epee::span<const cryptonote::txpool_event>);
+
+ template<typename F>
+ struct context
+ {
+ char const* const name;
+ F* generate_pub;
+ };
+
+ template<typename T>
+ bool operator<(const context<T>& lhs, const context<T>& rhs) noexcept
+ {
+ return std::strcmp(lhs.name, rhs.name) < 0;
+ }
+
+ template<typename T>
+ bool operator<(const context<T>& lhs, const boost::string_ref rhs) noexcept
+ {
+ return lhs.name < rhs;
+ }
+
+ struct is_valid
+ {
+ bool operator()(const cryptonote::txpool_event& event) const noexcept
+ {
+ return event.res;
+ }
+ };
+
+ template<typename T, std::size_t N>
+ void verify_sorted(const std::array<context<T>, N>& elems, const char* name)
+ {
+ auto unsorted = std::is_sorted_until(elems.begin(), elems.end());
+ if (unsorted != elems.end())
+ throw std::logic_error{name + std::string{" array is not properly sorted, see: "} + unsorted->name};
+ }
+
+ void write_header(epee::byte_stream& buf, const boost::string_ref name)
+ {
+ buf.write(name.data(), name.size());
+ buf.put(':');
+ }
+
+ //! \return `name:...` where `...` is JSON and `name` is directly copied (no quotes - not JSON).
+ template<typename T>
+ void json_pub(epee::byte_stream& buf, const T value)
+ {
+ rapidjson::Writer<epee::byte_stream> dest{buf};
+ using cryptonote::json::toJsonValue;
+ toJsonValue(dest, value);
+ }
+
+ //! Object for "minimal" block serialization
+ struct minimal_chain
+ {
+ const std::uint64_t height;
+ const epee::span<const cryptonote::block> blocks;
+ };
+
+ //! Object for "minimal" tx serialization
+ struct minimal_txpool
+ {
+ const cryptonote::transaction& tx;
+ };
+
+ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const minimal_chain self)
+ {
+ namespace adapt = boost::adaptors;
+
+ const auto to_block_id = [](const cryptonote::block& bl)
+ {
+ crypto::hash id;
+ if (!get_block_hash(bl, id))
+ MERROR("ZMQ/Pub failure: get_block_hash");
+ return id;
+ };
+
+ assert(!self.blocks.empty()); // checked in zmq_pub::send_chain_main
+
+ dest.StartObject();
+ INSERT_INTO_JSON_OBJECT(dest, first_height, self.height);
+ INSERT_INTO_JSON_OBJECT(dest, first_prev_id, self.blocks[0].prev_id);
+ INSERT_INTO_JSON_OBJECT(dest, ids, (self.blocks | adapt::transformed(to_block_id)));
+ dest.EndObject();
+ }
+
+ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const minimal_txpool self)
+ {
+ crypto::hash id{};
+ std::size_t blob_size = 0;
+ if (!get_transaction_hash(self.tx, id, blob_size))
+ {
+ MERROR("ZMQ/Pub failure: get_transaction_hash");
+ return;
+ }
+
+ dest.StartObject();
+ INSERT_INTO_JSON_OBJECT(dest, id, id);
+ INSERT_INTO_JSON_OBJECT(dest, blob_size, blob_size);
+ dest.EndObject();
+ }
+
+ void json_full_chain(epee::byte_stream& buf, const std::uint64_t height, const epee::span<const cryptonote::block> blocks)
+ {
+ json_pub(buf, blocks);
+ }
+
+ void json_minimal_chain(epee::byte_stream& buf, const std::uint64_t height, const epee::span<const cryptonote::block> blocks)
+ {
+ json_pub(buf, minimal_chain{height, blocks});
+ }
+
+ // boost::adaptors are in place "views" - no copy/move takes place
+ // moving transactions (via sort, etc.), is expensive!
+
+ void json_full_txpool(epee::byte_stream& buf, epee::span<const cryptonote::txpool_event> txes)
+ {
+ namespace adapt = boost::adaptors;
+ const auto to_full_tx = [](const cryptonote::txpool_event& event)
+ {
+ return event.tx;
+ };
+ json_pub(buf, (txes | adapt::filtered(is_valid{}) | adapt::transformed(to_full_tx)));
+ }
+
+ void json_minimal_txpool(epee::byte_stream& buf, epee::span<const cryptonote::txpool_event> txes)
+ {
+ namespace adapt = boost::adaptors;
+ const auto to_minimal_tx = [](const cryptonote::txpool_event& event)
+ {
+ return minimal_txpool{event.tx};
+ };
+ json_pub(buf, (txes | adapt::filtered(is_valid{}) | adapt::transformed(to_minimal_tx)));
+ }
+
+ constexpr const std::array<context<chain_writer>, 2> chain_contexts =
+ {{
+ {u8"json-full-chain_main", json_full_chain},
+ {u8"json-minimal-chain_main", json_minimal_chain}
+ }};
+
+ constexpr const std::array<context<txpool_writer>, 2> txpool_contexts =
+ {{
+ {u8"json-full-txpool_add", json_full_txpool},
+ {u8"json-minimal-txpool_add", json_minimal_txpool}
+ }};
+
+ template<typename T, std::size_t N>
+ epee::span<const context<T>> get_range(const std::array<context<T>, N>& contexts, const boost::string_ref value)
+ {
+ const auto not_prefix = [](const boost::string_ref lhs, const context<T>& rhs)
+ {
+ return !(boost::string_ref{rhs.name}.starts_with(lhs));
+ };
+
+ const auto lower = std::lower_bound(contexts.begin(), contexts.end(), value);
+ const auto upper = std::upper_bound(lower, contexts.end(), value, not_prefix);
+ return {lower, std::size_t(upper - lower)};
+ }
+
+ template<std::size_t N, typename T>
+ void add_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first)
+ {
+ assert(range.size() <= N);
+ assert(range.begin() - first <= N - range.size());
+
+ for (const auto& ctx : range)
+ {
+ const std::size_t i = std::addressof(ctx) - first;
+ subs[i] = std::min(std::numeric_limits<std::size_t>::max() - 1, subs[i]) + 1;
+ }
+ }
+
+ template<std::size_t N, typename T>
+ void remove_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first)
+ {
+ assert(range.size() <= N);
+ assert(range.begin() - first <= N - range.size());
+
+ for (const auto& ctx : range)
+ {
+ const std::size_t i = std::addressof(ctx) - first;
+ subs[i] = std::max(std::size_t(1), subs[i]) - 1;
+ }
+ }
+
+ template<std::size_t N, typename T, typename... U>
+ std::array<epee::byte_slice, N> make_pubs(const std::array<std::size_t, N>& subs, const std::array<context<T>, N>& contexts, U&&... args)
+ {
+ epee::byte_stream buf{};
+
+ std::size_t last_offset = 0;
+ std::array<std::size_t, N> offsets{{}};
+ for (std::size_t i = 0; i < N; ++i)
+ {
+ if (subs[i])
+ {
+ write_header(buf, contexts[i].name);
+ contexts[i].generate_pub(buf, std::forward<U>(args)...);
+ offsets[i] = buf.size() - last_offset;
+ last_offset = buf.size();
+ }
+ }
+
+ epee::byte_slice bytes{std::move(buf)};
+ std::array<epee::byte_slice, N> out;
+ for (std::size_t i = 0; i < N; ++i)
+ out[i] = bytes.take_slice(offsets[i]);
+
+ return out;
+ }
+
+ template<std::size_t N>
+ std::size_t send_messages(void* const socket, std::array<epee::byte_slice, N>& messages)
+ {
+ std::size_t count = 0;
+ for (epee::byte_slice& message : messages)
+ {
+ if (!message.empty())
+ {
+ const expect<void> sent = net::zmq::send(std::move(message), socket, ZMQ_DONTWAIT);
+ if (!sent)
+ MERROR("Failed to send ZMQ/Pub message: " << sent.error().message());
+ else
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ expect<bool> relay_block_pub(void* const relay, void* const pub) noexcept
+ {
+ zmq_msg_t msg;
+ zmq_msg_init(std::addressof(msg));
+ MONERO_CHECK(net::zmq::retry_op(zmq_msg_recv, std::addressof(msg), relay, ZMQ_DONTWAIT));
+
+ const boost::string_ref payload{
+ reinterpret_cast<const char*>(zmq_msg_data(std::addressof(msg))),
+ zmq_msg_size(std::addressof(msg))
+ };
+
+ if (payload == txpool_signal)
+ {
+ zmq_msg_close(std::addressof(msg));
+ return false;
+ }
+
+ // forward block messages (serialized on P2P thread for now)
+ const expect<void> sent = net::zmq::retry_op(zmq_msg_send, std::addressof(msg), pub, ZMQ_DONTWAIT);
+ if (!sent)
+ {
+ zmq_msg_close(std::addressof(msg));
+ return sent.error();
+ }
+ return true;
+ }
+} // anonymous
+
+namespace cryptonote { namespace listener
+{
+
+zmq_pub::zmq_pub(void* context)
+ : relay_(),
+ chain_subs_{{0}},
+ txpool_subs_{{0}},
+ sync_()
+{
+ if (!context)
+ throw std::logic_error{"ZMQ context cannot be NULL"};
+
+ verify_sorted(chain_contexts, "chain_contexts");
+ verify_sorted(txpool_contexts, "txpool_contexts");
+
+ relay_.reset(zmq_socket(context, ZMQ_PAIR));
+ if (!relay_)
+ MONERO_ZMQ_THROW("Failed to create relay socket");
+ if (zmq_connect(relay_.get(), relay_endpoint()) != 0)
+ MONERO_ZMQ_THROW("Failed to connect relay socket");
+}
+
+zmq_pub::~zmq_pub()
+{}
+
+bool zmq_pub::sub_request(boost::string_ref message)
+{
+ if (!message.empty())
+ {
+ const char tag = message[0];
+ message.remove_prefix(1);
+
+ const auto chain_range = get_range(chain_contexts, message);
+ const auto txpool_range = get_range(txpool_contexts, message);
+
+ if (!chain_range.empty() || !txpool_range.empty())
+ {
+ MDEBUG("Client " << (tag ? "subscribed" : "unsubscribed") << " to " <<
+ chain_range.size() << " chain topic(s) and " << txpool_range.size() << " txpool topic(s)");
+
+ const boost::lock_guard<boost::mutex> lock{sync_};
+ switch (tag)
+ {
+ case 0:
+ remove_subscriptions(chain_subs_, chain_range, chain_contexts.begin());
+ remove_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin());
+ return true;
+ case 1:
+ add_subscriptions(chain_subs_, chain_range, chain_contexts.begin());
+ add_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin());
+ return true;
+ default:
+ break;
+ }
+ }
+ }
+ MERROR("Invalid ZMQ/Sub message");
+ return false;
+}
+
+bool zmq_pub::relay_to_pub(void* const relay, void* const pub)
+{
+ const expect<bool> relayed = relay_block_pub(relay, pub);
+ if (!relayed)
+ {
+ MERROR("Error relaying ZMQ/Pub: " << relayed.error().message());
+ return false;
+ }
+
+ if (!*relayed)
+ {
+ std::array<std::size_t, 2> subs;
+ std::vector<cryptonote::txpool_event> events;
+ {
+ const boost::lock_guard<boost::mutex> lock{sync_};
+ if (txes_.empty())
+ return false;
+
+ subs = txpool_subs_;
+ events = std::move(txes_.front());
+ txes_.pop_front();
+ }
+ auto messages = make_pubs(subs, txpool_contexts, epee::to_span(events));
+ send_messages(pub, messages);
+ MDEBUG("Sent txpool ZMQ/Pub");
+ }
+ else
+ MDEBUG("Sent chain_main ZMQ/Pub");
+
+ return true;
+}
+
+std::size_t zmq_pub::send_chain_main(const std::uint64_t height, const epee::span<const cryptonote::block> blocks)
+{
+ if (blocks.empty())
+ return 0;
+
+ /* Block format only sends one block at a time - multiple block notifications
+ are less common and only occur on rollbacks. */
+
+ boost::unique_lock<boost::mutex> guard{sync_};
+
+ const auto subs_copy = chain_subs_;
+ guard.unlock();
+
+ for (const std::size_t sub : subs_copy)
+ {
+ if (sub)
+ {
+ /* cryptonote_core/blockchain.cpp cannot "give" us the block like core
+ does for txpool events. Since copying the block is expensive anyway,
+ serialization is done right here on the p2p thread (for now). */
+
+ auto messages = make_pubs(subs_copy, chain_contexts, height, blocks);
+ guard.lock();
+ return send_messages(relay_.get(), messages);
+ }
+ }
+ return 0;
+}
+
+std::size_t zmq_pub::send_txpool_add(std::vector<txpool_event> txes)
+{
+ if (txes.empty())
+ return 0;
+
+ const boost::lock_guard<boost::mutex> lock{sync_};
+ for (const std::size_t sub : txpool_subs_)
+ {
+ if (sub)
+ {
+ const expect<void> sent = net::zmq::retry_op(zmq_send_const, relay_.get(), txpool_signal, sizeof(txpool_signal) - 1, ZMQ_DONTWAIT);
+ if (sent)
+ txes_.emplace_back(std::move(txes));
+ else
+ MERROR("ZMQ/Pub failure, relay queue error: " << sent.error().message());
+ return bool(sent);
+ }
+ }
+ return 0;
+}
+
+void zmq_pub::chain_main::operator()(const std::uint64_t height, epee::span<const cryptonote::block> blocks) const
+{
+ const std::shared_ptr<zmq_pub> self = self_.lock();
+ if (self)
+ self->send_chain_main(height, blocks);
+ else
+ MERROR("Unable to send ZMQ/Pub - ZMQ server destroyed");
+}
+
+void zmq_pub::txpool_add::operator()(std::vector<cryptonote::txpool_event> txes) const
+{
+ const std::shared_ptr<zmq_pub> self = self_.lock();
+ if (self)
+ self->send_txpool_add(std::move(txes));
+ else
+ MERROR("Unable to send ZMQ/Pub - ZMQ server destroyed");
+}
+
+}}
diff --git a/src/rpc/zmq_pub.h b/src/rpc/zmq_pub.h
new file mode 100644
index 000000000..02e6b8103
--- /dev/null
+++ b/src/rpc/zmq_pub.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+ //
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <array>
+#include <boost/thread/mutex.hpp>
+#include <boost/utility/string_ref.hpp>
+#include <cstdint>
+#include <deque>
+#include <memory>
+#include <vector>
+
+#include "cryptonote_basic/fwd.h"
+#include "net/zmq.h"
+#include "span.h"
+
+namespace cryptonote { namespace listener
+{
+/*! \brief Sends ZMQ PUB messages on cryptonote events
+
+ Clients must ensure that all transaction(s) are notified before any blocks
+ they are contained in, and must ensure that each block is notified in chain
+ order. An external lock **must** be held by clients during the entire
+ txpool check and notification sequence and (a possibly second) lock is held
+ during the entire block check and notification sequence. Otherwise, events
+ could be sent in a different order than processed. */
+class zmq_pub
+{
+ /* Each socket has its own internal queue. So we can only use one socket, else
+ the messages being published are not guaranteed to be in the same order
+ pushed. */
+
+ net::zmq::socket relay_;
+ std::deque<std::vector<txpool_event>> txes_;
+ std::array<std::size_t, 2> chain_subs_;
+ std::array<std::size_t, 2> txpool_subs_;
+ boost::mutex sync_; //!< Synchronizes counts in `*_subs_` arrays.
+
+ public:
+ //! \return Name of ZMQ_PAIR endpoint for pub notifications
+ static constexpr const char* relay_endpoint() noexcept { return "inproc://pub_relay"; }
+
+ explicit zmq_pub(void* context);
+
+ zmq_pub(const zmq_pub&) = delete;
+ zmq_pub(zmq_pub&&) = delete;
+
+ ~zmq_pub();
+
+ zmq_pub& operator=(const zmq_pub&) = delete;
+ zmq_pub& operator=(zmq_pub&&) = delete;
+
+ //! Process a client subscription request (from XPUB sockets). Thread-safe.
+ bool sub_request(const boost::string_ref message);
+
+ /*! Forward ZMQ messages sent to `relay` via `send_chain_main` or
+ `send_txpool_add` to `pub`. Used by `ZmqServer`. */
+ bool relay_to_pub(void* relay, void* pub);
+
+ /*! Send a `ZMQ_PUB` notification for a change to the main chain.
+ Thread-safe.
+ \return Number of ZMQ messages sent to relay. */
+ std::size_t send_chain_main(std::uint64_t height, epee::span<const cryptonote::block> blocks);
+
+ /*! Send a `ZMQ_PUB` notification for new tx(es) being added to the local
+ pool. Thread-safe.
+ \return Number of ZMQ messages sent to relay. */
+ std::size_t send_txpool_add(std::vector<cryptonote::txpool_event> txes);
+
+ //! Callable for `send_chain_main` with weak ownership to `zmq_pub` object.
+ struct chain_main
+ {
+ std::weak_ptr<zmq_pub> self_;
+ void operator()(std::uint64_t height, epee::span<const cryptonote::block> blocks) const;
+ };
+
+ //! Callable for `send_txpool_add` with weak ownership to `zmq_pub` object.
+ struct txpool_add
+ {
+ std::weak_ptr<zmq_pub> self_;
+ void operator()(std::vector<cryptonote::txpool_event> txes) const;
+ };
+ };
+}}
diff --git a/src/rpc/zmq_server.cpp b/src/rpc/zmq_server.cpp
index 91e4751d1..6105b7f3a 100644
--- a/src/rpc/zmq_server.cpp
+++ b/src/rpc/zmq_server.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
@@ -28,12 +28,17 @@
#include "zmq_server.h"
-#include <boost/utility/string_ref.hpp>
#include <chrono>
-#include <cstdint>
+#include <cstring>
+#include <utility>
+#include <stdexcept>
#include <system_error>
#include "byte_slice.h"
+#include "rpc/zmq_pub.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.zmq"
namespace cryptonote
{
@@ -43,14 +48,57 @@ namespace
constexpr const int num_zmq_threads = 1;
constexpr const std::int64_t max_message_size = 10 * 1024 * 1024; // 10 MiB
constexpr const std::chrono::seconds linger_timeout{2}; // wait period for pending out messages
-}
+
+ net::zmq::socket init_socket(void* context, int type, epee::span<const std::string> addresses)
+ {
+ if (context == nullptr)
+ throw std::logic_error{"NULL context provided"};
+
+ net::zmq::socket out{};
+ out.reset(zmq_socket(context, type));
+ if (!out)
+ {
+ MONERO_LOG_ZMQ_ERROR("Failed to create ZMQ socket");
+ return nullptr;
+ }
+
+ if (zmq_setsockopt(out.get(), ZMQ_MAXMSGSIZE, std::addressof(max_message_size), sizeof(max_message_size)) != 0)
+ {
+ MONERO_LOG_ZMQ_ERROR("Failed to set maximum incoming message size");
+ return nullptr;
+ }
+
+ static constexpr const int linger_value = std::chrono::milliseconds{linger_timeout}.count();
+ if (zmq_setsockopt(out.get(), ZMQ_LINGER, std::addressof(linger_value), sizeof(linger_value)) != 0)
+ {
+ MONERO_LOG_ZMQ_ERROR("Failed to set linger timeout");
+ return nullptr;
+ }
+
+ for (const std::string& address : addresses)
+ {
+ if (zmq_bind(out.get(), address.c_str()) < 0)
+ {
+ MONERO_LOG_ZMQ_ERROR("ZMQ bind failed");
+ return nullptr;
+ }
+ MINFO("ZMQ now listening at " << address);
+ }
+
+ return out;
+ }
+} // anonymous
namespace rpc
{
ZmqServer::ZmqServer(RpcHandler& h) :
handler(h),
- context(zmq_init(num_zmq_threads))
+ context(zmq_init(num_zmq_threads)),
+ rep_socket(nullptr),
+ pub_socket(nullptr),
+ relay_socket(nullptr),
+ shared_state(nullptr)
{
if (!context)
MONERO_ZMQ_THROW("Unable to create ZMQ context");
@@ -65,22 +113,59 @@ void ZmqServer::serve()
try
{
// socket must close before `zmq_term` will exit.
- const net::zmq::socket socket = std::move(rep_socket);
- if (!socket)
+ const net::zmq::socket rep = std::move(rep_socket);
+ const net::zmq::socket pub = std::move(pub_socket);
+ const net::zmq::socket relay = std::move(relay_socket);
+ const std::shared_ptr<listener::zmq_pub> state = std::move(shared_state);
+
+ const unsigned init_count = unsigned(bool(pub)) + bool(relay) + bool(state);
+ if (!rep || (init_count && init_count != 3))
{
- MERROR("ZMQ RPC server reply socket is null");
+ MERROR("ZMQ RPC server socket is null");
return;
}
+ MINFO("ZMQ Server started");
+
+ const int read_flags = pub ? ZMQ_DONTWAIT : 0;
+ std::array<zmq_pollitem_t, 3> sockets =
+ {{
+ {relay.get(), 0, ZMQ_POLLIN, 0},
+ {pub.get(), 0, ZMQ_POLLIN, 0},
+ {rep.get(), 0, ZMQ_POLLIN, 0}
+ }};
+
+ /* This uses XPUB to watch for subscribers, to reduce CPU cycles for
+ serialization when the data will be dropped. This is important for block
+ serialization, which is done on the p2p threads currently (see
+ zmq_pub.cpp).
+
+ XPUB sockets are not thread-safe, so the p2p thread cannot write into
+ the socket while we read here for subscribers. A ZMQ_PAIR socket is
+ used for inproc notification. No data is every copied to kernel, it is
+ all userspace messaging. */
+
while (1)
{
- const std::string message = MONERO_UNWRAP(net::zmq::receive(socket.get()));
- MDEBUG("Received RPC request: \"" << message << "\"");
- epee::byte_slice response = handler.handle(message);
+ if (pub)
+ MONERO_UNWRAP(net::zmq::retry_op(zmq_poll, sockets.data(), sockets.size(), -1));
- const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
- MDEBUG("Sending RPC reply: \"" << response_view << "\"");
- MONERO_UNWRAP(net::zmq::send(std::move(response), socket.get()));
+ if (sockets[0].revents)
+ state->relay_to_pub(relay.get(), pub.get());
+
+ if (sockets[1].revents)
+ state->sub_request(MONERO_UNWRAP(net::zmq::receive(pub.get(), ZMQ_DONTWAIT)));
+
+ if (!pub || sockets[2].revents)
+ {
+ const std::string message = MONERO_UNWRAP(net::zmq::receive(rep.get(), read_flags));
+ MDEBUG("Received RPC request: \"" << message << "\"");
+ epee::byte_slice response = handler.handle(message);
+
+ const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
+ MDEBUG("Sending RPC reply: \"" << response_view << "\"");
+ MONERO_UNWRAP(net::zmq::send(std::move(response), rep.get()));
+ }
}
}
catch (const std::system_error& e)
@@ -98,38 +183,12 @@ void ZmqServer::serve()
}
}
-bool ZmqServer::addIPCSocket(const boost::string_ref address, const boost::string_ref port)
-{
- MERROR("ZmqServer::addIPCSocket not yet implemented!");
- return false;
-}
-
-bool ZmqServer::addTCPSocket(boost::string_ref address, boost::string_ref port)
+void* ZmqServer::init_rpc(boost::string_ref address, boost::string_ref port)
{
if (!context)
{
MERROR("ZMQ RPC Server already shutdown");
- return false;
- }
-
- rep_socket.reset(zmq_socket(context.get(), ZMQ_REP));
- if (!rep_socket)
- {
- MONERO_LOG_ZMQ_ERROR("ZMQ RPC Server socket create failed");
- return false;
- }
-
- if (zmq_setsockopt(rep_socket.get(), ZMQ_MAXMSGSIZE, std::addressof(max_message_size), sizeof(max_message_size)) != 0)
- {
- MONERO_LOG_ZMQ_ERROR("Failed to set maximum incoming message size");
- return false;
- }
-
- static constexpr const int linger_value = std::chrono::milliseconds{linger_timeout}.count();
- if (zmq_setsockopt(rep_socket.get(), ZMQ_LINGER, std::addressof(linger_value), sizeof(linger_value)) != 0)
- {
- MONERO_LOG_ZMQ_ERROR("Failed to set linger timeout");
- return false;
+ return nullptr;
}
if (address.empty())
@@ -142,12 +201,34 @@ bool ZmqServer::addTCPSocket(boost::string_ref address, boost::string_ref port)
bind_address += ":";
bind_address.append(port.data(), port.size());
- if (zmq_bind(rep_socket.get(), bind_address.c_str()) < 0)
+ rep_socket = init_socket(context.get(), ZMQ_REP, {std::addressof(bind_address), 1});
+ return bool(rep_socket) ? context.get() : nullptr;
+}
+
+std::shared_ptr<listener::zmq_pub> ZmqServer::init_pub(epee::span<const std::string> addresses)
+{
+ try
+ {
+ shared_state = std::make_shared<listener::zmq_pub>(context.get());
+ pub_socket = init_socket(context.get(), ZMQ_XPUB, addresses);
+ if (!pub_socket)
+ throw std::runtime_error{"Unable to initialize ZMQ_XPUB socket"};
+
+ const std::string relay_address[] = {listener::zmq_pub::relay_endpoint()};
+ relay_socket = init_socket(context.get(), ZMQ_PAIR, relay_address);
+ if (!relay_socket)
+ throw std::runtime_error{"Unable to initialize ZMQ_PAIR relay"};
+ }
+ catch (const std::runtime_error& e)
{
- MONERO_LOG_ZMQ_ERROR("ZMQ RPC Server bind failed");
- return false;
+ shared_state = nullptr;
+ pub_socket = nullptr;
+ relay_socket = nullptr;
+ MERROR("Failed to create ZMQ/Pub listener: " << e.what());
+ return nullptr;
}
- return true;
+
+ return shared_state;
}
void ZmqServer::run()
@@ -164,7 +245,6 @@ void ZmqServer::stop()
run_thread.join();
}
-
} // namespace cryptonote
} // namespace rpc
diff --git a/src/rpc/zmq_server.h b/src/rpc/zmq_server.h
index ce7892dab..ddf44b411 100644
--- a/src/rpc/zmq_server.h
+++ b/src/rpc/zmq_server.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
@@ -30,10 +30,16 @@
#include <boost/thread/thread.hpp>
#include <boost/utility/string_ref.hpp>
+#include <cstdint>
+#include <memory>
+#include <string>
#include "common/command_line.h"
+#include "cryptonote_basic/fwd.h"
#include "net/zmq.h"
-#include "rpc_handler.h"
+#include "rpc/fwd.h"
+#include "rpc/rpc_handler.h"
+#include "span.h"
namespace cryptonote
{
@@ -41,7 +47,7 @@ namespace cryptonote
namespace rpc
{
-class ZmqServer
+class ZmqServer final
{
public:
@@ -49,12 +55,13 @@ class ZmqServer
~ZmqServer();
- static void init_options(boost::program_options::options_description& desc);
-
void serve();
- bool addIPCSocket(boost::string_ref address, boost::string_ref port);
- bool addTCPSocket(boost::string_ref address, boost::string_ref port);
+ //! \return ZMQ context on success, `nullptr` on failure
+ void* init_rpc(boost::string_ref address, boost::string_ref port);
+
+ //! \return `nullptr` on errors.
+ std::shared_ptr<listener::zmq_pub> init_pub(epee::span<const std::string> addresses);
void run();
void stop();
@@ -67,9 +74,11 @@ class ZmqServer
boost::thread run_thread;
net::zmq::socket rep_socket;
+ net::zmq::socket pub_socket;
+ net::zmq::socket relay_socket;
+ std::shared_ptr<listener::zmq_pub> shared_state;
};
-
} // namespace cryptonote
} // namespace rpc
diff --git a/src/serialization/CMakeLists.txt b/src/serialization/CMakeLists.txt
index 0b231f156..a2e7c353e 100644
--- a/src/serialization/CMakeLists.txt
+++ b/src/serialization/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2016-2019, The Monero Project
+# Copyright (c) 2016-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h
index 9f60cf311..80104c8f7 100644
--- a/src/serialization/binary_archive.h
+++ b/src/serialization/binary_archive.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/binary_utils.h b/src/serialization/binary_utils.h
index 790661e49..8635585af 100644
--- a/src/serialization/binary_utils.h
+++ b/src/serialization/binary_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/container.h b/src/serialization/container.h
index dfe0f9691..4bf47ecfa 100644
--- a/src/serialization/container.h
+++ b/src/serialization/container.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h
index d2537146e..42bd06e92 100644
--- a/src/serialization/crypto.h
+++ b/src/serialization/crypto.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/debug_archive.h b/src/serialization/debug_archive.h
index 093ca41eb..b04d6ae19 100644
--- a/src/serialization/debug_archive.h
+++ b/src/serialization/debug_archive.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/deque.h b/src/serialization/deque.h
index 97f16d0a5..b029ed430 100644
--- a/src/serialization/deque.h
+++ b/src/serialization/deque.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/difficulty_type.h b/src/serialization/difficulty_type.h
index c551095f9..56c0312e7 100644
--- a/src/serialization/difficulty_type.h
+++ b/src/serialization/difficulty_type.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/json_archive.h b/src/serialization/json_archive.h
index c9f4e175e..50dd5bbd0 100644
--- a/src/serialization/json_archive.h
+++ b/src/serialization/json_archive.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp
index f20fd181a..5c042aa7b 100644
--- a/src/serialization/json_object.cpp
+++ b/src/serialization/json_object.cpp
@@ -120,18 +120,18 @@ void read_hex(const rapidjson::Value& val, epee::span<std::uint8_t> dest)
throw WRONG_TYPE("string");
}
- if (!epee::from_hex::to_buffer(dest, {val.GetString(), val.Size()}))
+ if (!epee::from_hex::to_buffer(dest, {val.GetString(), val.GetStringLength()}))
{
throw BAD_INPUT();
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rapidjson::Value& src)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rapidjson::Value& src)
{
src.Accept(dest);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const boost::string_ref i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const boost::string_ref i)
{
dest.String(i.data(), i.size());
}
@@ -146,7 +146,7 @@ void fromJsonValue(const rapidjson::Value& val, std::string& str)
str = val.GetString();
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, bool i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, bool i)
{
dest.Bool(i);
}
@@ -185,7 +185,7 @@ void fromJsonValue(const rapidjson::Value& val, short& i)
to_int(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned int i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned int i)
{
dest.Uint(i);
}
@@ -195,7 +195,7 @@ void fromJsonValue(const rapidjson::Value& val, unsigned int& i)
to_uint(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const int i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const int i)
{
dest.Int(i);
}
@@ -205,7 +205,7 @@ void fromJsonValue(const rapidjson::Value& val, int& i)
to_int(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned long long i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned long long i)
{
static_assert(!precision_loss<unsigned long long, std::uint64_t>(), "bad uint64 conversion");
dest.Uint64(i);
@@ -216,7 +216,7 @@ void fromJsonValue(const rapidjson::Value& val, unsigned long long& i)
to_uint64(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const long long i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const long long i)
{
static_assert(!precision_loss<long long, std::int64_t>(), "bad int64 conversion");
dest.Int64(i);
@@ -237,7 +237,7 @@ void fromJsonValue(const rapidjson::Value& val, long& i)
to_int64(val, i);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::transaction& tx)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::transaction& tx)
{
dest.StartObject();
@@ -269,7 +269,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx)
GET_FROM_JSON_OBJECT(val, tx.rct_signatures, ringct);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block& b)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block& b)
{
dest.StartObject();
@@ -301,14 +301,14 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b)
GET_FROM_JSON_OBJECT(val, b.tx_hashes, tx_hashes);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_v& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_v& txin)
{
dest.StartObject();
struct add_input
{
using result_type = void;
- rapidjson::Writer<rapidjson::StringBuffer>& dest;
+ rapidjson::Writer<epee::byte_stream>& dest;
void operator()(cryptonote::txin_to_key const& input) const
{
@@ -373,7 +373,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_v& txin)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_gen& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_gen& txin)
{
dest.StartObject();
@@ -392,7 +392,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_gen& txin)
GET_FROM_JSON_OBJECT(val, txin.height, height);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_script& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_script& txin)
{
dest.StartObject();
@@ -417,7 +417,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_scripthash& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_scripthash& txin)
{
dest.StartObject();
@@ -443,7 +443,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash&
GET_FROM_JSON_OBJECT(val, txin.sigset, sigset);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_key& txin)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_key& txin)
{
dest.StartObject();
@@ -467,7 +467,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin)
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_script& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_script& txout)
{
dest.StartObject();
@@ -489,7 +489,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txo
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_scripthash& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_scripthash& txout)
{
dest.StartObject();
@@ -509,7 +509,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_scripthash&
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_key& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_key& txout)
{
dest.StartObject();
@@ -528,7 +528,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_key& txout)
GET_FROM_JSON_OBJECT(val, txout.key, key);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_out& txout)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_out& txout)
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, amount, txout.amount);
@@ -537,7 +537,7 @@ void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const crypton
{
using result_type = void;
- rapidjson::Writer<rapidjson::StringBuffer>& dest;
+ rapidjson::Writer<epee::byte_stream>& dest;
void operator()(cryptonote::txout_to_key const& output) const
{
@@ -596,7 +596,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_out& txout)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::connection_info& info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::connection_info& info)
{
dest.StartObject();
@@ -668,7 +668,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::connection_info& inf
GET_FROM_JSON_OBJECT(val, info.current_upload, current_upload);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_blob_entry& tx)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_blob_entry& tx)
{
dest.StartObject();
@@ -689,7 +689,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_blob_entry& tx)
GET_FROM_JSON_OBJECT(val, tx.prunable_hash, prunable_hash);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block_complete_entry& blk)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block_complete_entry& blk)
{
dest.StartObject();
@@ -711,7 +711,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::block_complete_entry
GET_FROM_JSON_OBJECT(val, blk.txs, transactions);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::block_with_transactions& blk)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::block_with_transactions& blk)
{
dest.StartObject();
@@ -733,7 +733,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::block_with_tran
GET_FROM_JSON_OBJECT(val, blk.transactions, transactions);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::transaction_info& tx_info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::transaction_info& tx_info)
{
dest.StartObject();
@@ -757,7 +757,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::transaction_inf
GET_FROM_JSON_OBJECT(val, tx_info.transaction, transaction);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_and_amount_index& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_and_amount_index& out)
{
dest.StartObject();
@@ -779,7 +779,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_and_
GET_FROM_JSON_OBJECT(val, out.key, key);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::amount_with_random_outputs& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::amount_with_random_outputs& out)
{
dest.StartObject();
@@ -801,7 +801,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::amount_with_ran
GET_FROM_JSON_OBJECT(val, out.outputs, outputs);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::peer& peer)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::peer& peer)
{
dest.StartObject();
@@ -833,7 +833,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::peer& peer)
GET_FROM_JSON_OBJECT(val, peer.pruning_seed, pruning_seed);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::tx_in_pool& tx)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::tx_in_pool& tx)
{
dest.StartObject();
@@ -880,7 +880,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx)
GET_FROM_JSON_OBJECT(val, tx.double_spend_seen, double_spend_seen);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::hard_fork_info& info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::hard_fork_info& info)
{
dest.StartObject();
@@ -914,7 +914,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::hard_fork_info&
GET_FROM_JSON_OBJECT(val, info.earliest_height, earliest_height);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_count& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_count& out)
{
dest.StartObject();
@@ -940,7 +940,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_c
GET_FROM_JSON_OBJECT(val, out.recent_count, recent_count);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_and_index& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_and_index& out)
{
dest.StartObject();
@@ -962,7 +962,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_a
GET_FROM_JSON_OBJECT(val, out.index, index);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_mask_unlocked& out)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_mask_unlocked& out)
{
dest.StartObject();
@@ -985,7 +985,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_mask
GET_FROM_JSON_OBJECT(val, out.unlocked, unlocked);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::error& err)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::error& err)
{
dest.StartObject();
@@ -1008,7 +1008,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error)
GET_FROM_JSON_OBJECT(val, error.message, message);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::BlockHeaderResponse& response)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::BlockHeaderResponse& response)
{
dest.StartObject();
@@ -1045,7 +1045,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResp
GET_FROM_JSON_OBJECT(val, response.reward, reward);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rctSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig)
{
using boost::adaptors::transform;
@@ -1115,7 +1115,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::ecdhTuple& tuple)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::ecdhTuple& tuple)
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, mask, tuple.mask);
@@ -1134,7 +1134,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::ecdhTuple& tuple)
GET_FROM_JSON_OBJECT(val, tuple.amount, amount);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rangeSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rangeSig& sig)
{
dest.StartObject();
@@ -1171,7 +1171,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig)
}
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::Bulletproof& p)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::Bulletproof& p)
{
dest.StartObject();
@@ -1212,7 +1212,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p)
GET_FROM_JSON_OBJECT(val, p.t, t);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::boroSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::boroSig& sig)
{
dest.StartObject();
@@ -1257,7 +1257,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig)
GET_FROM_JSON_OBJECT(val, sig.ee, ee);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::mgSig& sig)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::mgSig& sig)
{
dest.StartObject();
@@ -1278,7 +1278,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig)
GET_FROM_JSON_OBJECT(val, sig.cc, cc);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::DaemonInfo& info)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info)
{
dest.StartObject();
@@ -1339,7 +1339,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
GET_FROM_JSON_OBJECT(val, info.start_time, start_time);
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_distribution& dist)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_distribution& dist)
{
dest.StartObject();
diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h
index 664b539b5..e016bef41 100644
--- a/src/serialization/json_object.h
+++ b/src/serialization/json_object.h
@@ -31,9 +31,9 @@
#include <boost/utility/string_ref.hpp>
#include <cstring>
#include <rapidjson/document.h>
-#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
+#include "byte_stream.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "rpc/message_data_structs.h"
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
@@ -123,7 +123,7 @@ void read_hex(const rapidjson::Value& val, epee::span<std::uint8_t> dest);
// POD to json key
template <class Type>
-inline typename std::enable_if<is_to_hex<Type>()>::type toJsonKey(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Type& pod)
+inline typename std::enable_if<is_to_hex<Type>()>::type toJsonKey(rapidjson::Writer<epee::byte_stream>& dest, const Type& pod)
{
const auto hex = epee::to_hex::array(pod);
dest.Key(hex.data(), hex.size());
@@ -131,7 +131,7 @@ inline typename std::enable_if<is_to_hex<Type>()>::type toJsonKey(rapidjson::Wri
// POD to json value
template <class Type>
-inline typename std::enable_if<is_to_hex<Type>()>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Type& pod)
+inline typename std::enable_if<is_to_hex<Type>()>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Type& pod)
{
const auto hex = epee::to_hex::array(pod);
dest.String(hex.data(), hex.size());
@@ -144,16 +144,16 @@ inline typename std::enable_if<is_to_hex<Type>()>::type fromJsonValue(const rapi
json::read_hex(val, epee::as_mut_byte_span(t));
}
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rapidjson::Value& src);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rapidjson::Value& src);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, boost::string_ref i);
-inline void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const std::string& i)
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, boost::string_ref i);
+inline void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const std::string& i)
{
toJsonValue(dest, boost::string_ref{i});
}
void fromJsonValue(const rapidjson::Value& val, std::string& str);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, bool i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, bool i);
void fromJsonValue(const rapidjson::Value& val, bool& b);
// integers overloads for toJsonValue are not needed for standard promotions
@@ -168,144 +168,144 @@ void fromJsonValue(const rapidjson::Value& val, unsigned short& i);
void fromJsonValue(const rapidjson::Value& val, short& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned i);
void fromJsonValue(const rapidjson::Value& val, unsigned& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const int);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const int);
void fromJsonValue(const rapidjson::Value& val, int& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned long long i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned long long i);
void fromJsonValue(const rapidjson::Value& val, unsigned long long& i);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const long long i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const long long i);
void fromJsonValue(const rapidjson::Value& val, long long& i);
-inline void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const unsigned long i) {
+inline void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const unsigned long i) {
toJsonValue(dest, static_cast<unsigned long long>(i));
}
void fromJsonValue(const rapidjson::Value& val, unsigned long& i);
-inline void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const long i) {
+inline void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const long i) {
toJsonValue(dest, static_cast<long long>(i));
}
void fromJsonValue(const rapidjson::Value& val, long& i);
// end integers
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::transaction& tx);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::transaction& tx);
void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block& b);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block& b);
void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_v& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_v& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_v& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_gen& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_gen& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_gen& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_script& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_script& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_scripthash& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_scripthash& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txin_to_key& txin);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_key& txin);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_target_v& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_target_v& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_target_v& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_script& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_script& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_scripthash& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_scripthash& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_scripthash& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::txout_to_key& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_to_key& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_key& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_out& txout);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_out& txout);
void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_out& txout);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::connection_info& info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::connection_info& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::connection_info& info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::tx_blob_entry& tx);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_blob_entry& tx);
void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_blob_entry& tx);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::block_complete_entry& blk);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::block_complete_entry& blk);
void fromJsonValue(const rapidjson::Value& val, cryptonote::block_complete_entry& blk);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::block_with_transactions& blk);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::block_with_transactions& blk);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::block_with_transactions& blk);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::transaction_info& tx_info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::transaction_info& tx_info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::transaction_info& tx_info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_and_amount_index& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_and_amount_index& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_and_amount_index& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::amount_with_random_outputs& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::amount_with_random_outputs& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::amount_with_random_outputs& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::peer& peer);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::peer& peer);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::peer& peer);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::tx_in_pool& tx);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::tx_in_pool& tx);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::hard_fork_info& info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::hard_fork_info& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::hard_fork_info& info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_count& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_count& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_count& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_amount_and_index& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_amount_and_index& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_and_index& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_key_mask_unlocked& out);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_key_mask_unlocked& out);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_mask_unlocked& out);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::error& err);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::error& err);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::BlockHeaderResponse& response);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::BlockHeaderResponse& response);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResponse& response);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rctSig& i);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& i);
void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::ecdhTuple& tuple);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::ecdhTuple& tuple);
void fromJsonValue(const rapidjson::Value& val, rct::ecdhTuple& tuple);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::rangeSig& sig);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rangeSig& sig);
void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::Bulletproof& p);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::Bulletproof& p);
void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::boroSig& sig);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::boroSig& sig);
void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const rct::mgSig& sig);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::mgSig& sig);
void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::DaemonInfo& info);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
-void toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const cryptonote::rpc::output_distribution& dist);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_distribution& dist);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_distribution& dist);
template <typename Map>
-typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Map& map);
+typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Map& map);
template <typename Map>
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type fromJsonValue(const rapidjson::Value& val, Map& map);
template <typename Vec>
-typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Vec &vec);
+typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Vec &vec);
template <typename Vec>
typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJsonValue(const rapidjson::Value& val, Vec& vec);
@@ -315,7 +315,7 @@ typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJson
// unfortunately because of how templates work they have to be here.
template <typename Map>
-inline typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Map& map)
+inline typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Map& map)
{
using key_type = typename Map::key_type;
static_assert(std::is_same<std::string, key_type>() || is_to_hex<key_type>(), "invalid map key type");
@@ -351,12 +351,12 @@ inline typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type from
}
template <typename Vec>
-inline typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<rapidjson::StringBuffer>& dest, const Vec &vec)
+inline typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Vec &vec)
{
dest.StartArray();
for (const auto& t : vec)
toJsonValue(dest, t);
- dest.EndArray(vec.size());
+ dest.EndArray();
}
template <typename Vec>
diff --git a/src/serialization/json_utils.h b/src/serialization/json_utils.h
index 05122f3bd..8115877dc 100644
--- a/src/serialization/json_utils.h
+++ b/src/serialization/json_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/list.h b/src/serialization/list.h
index b7b65e184..139269b40 100644
--- a/src/serialization/list.h
+++ b/src/serialization/list.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/pair.h b/src/serialization/pair.h
index aed0c4699..18280d837 100644
--- a/src/serialization/pair.h
+++ b/src/serialization/pair.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h
index 553e9951f..d0f9ee0f7 100644
--- a/src/serialization/serialization.h
+++ b/src/serialization/serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/set.h b/src/serialization/set.h
index ae602a2f1..157c002f7 100644
--- a/src/serialization/set.h
+++ b/src/serialization/set.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/string.h b/src/serialization/string.h
index fd8450f7b..f5f69833a 100644
--- a/src/serialization/string.h
+++ b/src/serialization/string.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/unordered_set.h b/src/serialization/unordered_set.h
index 6dd01fd93..24aa09437 100644
--- a/src/serialization/unordered_set.h
+++ b/src/serialization/unordered_set.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/variant.h b/src/serialization/variant.h
index 5a179ca87..b08cf6bf0 100644
--- a/src/serialization/variant.h
+++ b/src/serialization/variant.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/serialization/vector.h b/src/serialization/vector.h
index ad96582a5..1fca1d485 100644
--- a/src/serialization/vector.h
+++ b/src/serialization/vector.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt
index 030867dc0..a0820c8eb 100644
--- a/src/simplewallet/CMakeLists.txt
+++ b/src/simplewallet/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -49,6 +49,7 @@ target_link_libraries(simplewallet
common
mnemonics
${EPEE_READLINE}
+ qrcodegen
version
${Boost_CHRONO_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 4a22dfa25..d36e5009b 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,6 +33,11 @@
*
* \brief Source file that defines simple_wallet class.
*/
+
+// use boost bind placeholders for now
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS 1
+#include <boost/bind.hpp>
+
#include <locale.h>
#include <thread>
#include <iostream>
@@ -69,10 +74,12 @@
#include "version.h"
#include <stdexcept>
#include "wallet/message_store.h"
+#include "QrCode.hpp"
#ifdef WIN32
#include <boost/locale.hpp>
#include <boost/filesystem.hpp>
+#include <fcntl.h>
#endif
#ifdef HAVE_READLINE
@@ -143,6 +150,7 @@ enum TransferType {
};
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
+static std::string get_human_readable_timespan(uint64_t seconds);
namespace
{
@@ -249,6 +257,7 @@ namespace
const char* USAGE_MMS_SET("mms set <option_name> [<option_value>]");
const char* USAGE_MMS_SEND_SIGNER_CONFIG("mms send_signer_config");
const char* USAGE_MMS_START_AUTO_CONFIG("mms start_auto_config [<label> <label> ...]");
+ const char* USAGE_MMS_CONFIG_CHECKSUM("mms config_checksum");
const char* USAGE_MMS_STOP_AUTO_CONFIG("mms stop_auto_config");
const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
@@ -268,6 +277,7 @@ namespace
const char* USAGE_RPC_PAYMENT_INFO("rpc_payment_info");
const char* USAGE_START_MINING_FOR_RPC("start_mining_for_rpc");
const char* USAGE_STOP_MINING_FOR_RPC("stop_mining_for_rpc");
+ const char* USAGE_SHOW_QR_CODE("show_qr_code [<subaddress_index>]");
const char* USAGE_VERSION("version");
const char* USAGE_HELP_ADVANCED("help_advanced [<command>]");
const char* USAGE_HELP("help");
@@ -2387,6 +2397,62 @@ bool simple_wallet::stop_mining_for_rpc(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::show_qr_code(const std::vector<std::string> &args)
+{
+ uint32_t subaddress_index = 0;
+ if (args.size() >= 1)
+ {
+ if (!string_tools::get_xtype_from_string(subaddress_index, args[0]))
+ {
+ fail_msg_writer() << tr("invalid index: must be an unsigned integer");
+ return true;
+ }
+ if (subaddress_index >= m_wallet->get_num_subaddresses(m_current_subaddress_account))
+ {
+ fail_msg_writer() << tr("<subaddress_index> is out of bounds");
+ return true;
+ }
+ }
+
+#ifdef _WIN32
+#define PRINT_UTF8(pre, x) std::wcout << pre ## x
+#define WTEXTON() _setmode(_fileno(stdout), _O_WTEXT)
+#define WTEXTOFF() _setmode(_fileno(stdout), _O_TEXT)
+#else
+#define PRINT_UTF8(pre, x) std::cout << x
+#define WTEXTON()
+#define WTEXTOFF()
+#endif
+
+ WTEXTON();
+ try
+ {
+ const std::string address = "monero:" + m_wallet->get_subaddress_as_str({m_current_subaddress_account, subaddress_index});
+ const qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(address.c_str(), qrcodegen::QrCode::Ecc::LOW);
+ for (int y = -2; y < qr.getSize() + 2; y+=2)
+ {
+ for (int x = -2; x < qr.getSize() + 2; x++)
+ {
+ if (qr.getModule(x, y) && qr.getModule(x, y + 1))
+ PRINT_UTF8(L, "\u2588");
+ else if (qr.getModule(x, y) && !qr.getModule(x, y + 1))
+ PRINT_UTF8(L, "\u2580");
+ else if (!qr.getModule(x, y) && qr.getModule(x, y + 1))
+ PRINT_UTF8(L, "\u2584");
+ else
+ PRINT_UTF8(L, " ");
+ }
+ PRINT_UTF8(, std::endl);
+ }
+ }
+ catch (const std::length_error&)
+ {
+ fail_msg_writer() << tr("Failed to generate QR code, input too large");
+ }
+ WTEXTOFF();
+ return true;
+}
+
bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -3143,10 +3209,10 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_unmixable, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));
- m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1),
+ m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_all, _1),
tr(USAGE_SWEEP_ALL),
tr("Send all unlocked balance to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
- m_cmd_binder.set_handler("sweep_account", boost::bind(&simple_wallet::sweep_account, this, _1),
+ m_cmd_binder.set_handler("sweep_account", boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_account, _1),
tr(USAGE_SWEEP_ACCOUNT),
tr("Send all unlocked balance from a given account to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
m_cmd_binder.set_handler("sweep_below",
@@ -3210,7 +3276,7 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::on_command, this, &simple_wallet::seed, _1),
tr("Display the Electrum-style mnemonic seed"));
m_cmd_binder.set_handler("restore_height",
- boost::bind(&simple_wallet::restore_height, this, _1),
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::restore_height, _1),
tr("Display the restore height"));
m_cmd_binder.set_handler("set",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::set_variable, _1),
@@ -3459,7 +3525,7 @@ simple_wallet::simple_wallet()
tr("Interface with the MMS (Multisig Messaging System)\n"
"<subcommand> is one of:\n"
" init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n"
- " send_signer_config, start_auto_config, stop_auto_config, auto_config\n"
+ " send_signer_config, start_auto_config, stop_auto_config, auto_config, config_checksum\n"
"Get help about a subcommand with: help_advanced mms <subcommand>"));
m_cmd_binder.set_handler("mms init",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
@@ -3521,13 +3587,17 @@ simple_wallet::simple_wallet()
"auto-send <1|0>\n "
" Whether to automatically send newly generated messages right away.\n "));
m_cmd_binder.set_handler("mms send_signer_config",
- boost::bind(&simple_wallet::mms, this, _1),
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
tr(USAGE_MMS_SEND_SIGNER_CONFIG),
tr("Send completed signer config to all other authorized signers"));
m_cmd_binder.set_handler("mms start_auto_config",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
tr(USAGE_MMS_START_AUTO_CONFIG),
tr("Start auto-config at the auto-config manager's wallet by issuing auto-config tokens and optionally set others' labels"));
+ m_cmd_binder.set_handler("mms config_checksum",
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
+ tr(USAGE_MMS_CONFIG_CHECKSUM),
+ tr("Get a checksum that allows signers to easily check for identical MMS configuration"));
m_cmd_binder.set_handler("mms stop_auto_config",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
tr(USAGE_MMS_STOP_AUTO_CONFIG),
@@ -3587,7 +3657,7 @@ simple_wallet::simple_wallet()
tr(USAGE_NET_STATS),
tr("Prints simple network stats"));
m_cmd_binder.set_handler("public_nodes",
- boost::bind(&simple_wallet::public_nodes, this, _1),
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::public_nodes, _1),
tr(USAGE_PUBLIC_NODES),
tr("Lists known public nodes"));
m_cmd_binder.set_handler("welcome",
@@ -3599,17 +3669,21 @@ simple_wallet::simple_wallet()
tr(USAGE_VERSION),
tr("Returns version information"));
m_cmd_binder.set_handler("rpc_payment_info",
- boost::bind(&simple_wallet::rpc_payment_info, this, _1),
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::rpc_payment_info, _1),
tr(USAGE_RPC_PAYMENT_INFO),
tr("Get info about RPC payments to current node"));
m_cmd_binder.set_handler("start_mining_for_rpc",
- boost::bind(&simple_wallet::start_mining_for_rpc, this, _1),
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::start_mining_for_rpc, _1),
tr(USAGE_START_MINING_FOR_RPC),
tr("Start mining to pay for RPC access"));
m_cmd_binder.set_handler("stop_mining_for_rpc",
- boost::bind(&simple_wallet::stop_mining_for_rpc, this, _1),
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::stop_mining_for_rpc, _1),
tr(USAGE_STOP_MINING_FOR_RPC),
tr("Stop mining to pay for RPC access"));
+ m_cmd_binder.set_handler("show_qr_code",
+ boost::bind(&simple_wallet::on_command, this, &simple_wallet::show_qr_code, _1),
+ tr(USAGE_SHOW_QR_CODE),
+ tr("Show address as QR code"));
m_cmd_binder.set_handler("help_advanced",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::help_advanced, _1),
tr(USAGE_HELP_ADVANCED),
@@ -5465,7 +5539,7 @@ void simple_wallet::on_new_block(uint64_t height, const cryptonote::block& block
m_refresh_progress_reporter.update(height, false);
}
//----------------------------------------------------------------------------------------------------
-void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time)
+void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time)
{
if (m_locked)
return;
@@ -5476,7 +5550,7 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
tr("idx ") << subaddr_index;
const uint64_t warn_height = m_wallet->nettype() == TESTNET ? 1000000 : m_wallet->nettype() == STAGENET ? 50000 : 1650000;
- if (height >= warn_height)
+ if (height >= warn_height && !is_change)
{
std::vector<tx_extra_field> tx_extra_fields;
parse_tx_extra(tx.extra, tx_extra_fields); // failure ok
@@ -5757,15 +5831,19 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0});
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
- uint64_t blocks_to_unlock;
- uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock);
+ uint64_t blocks_to_unlock, time_to_unlock;
+ uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock, &time_to_unlock);
std::string unlock_time_message;
- if (blocks_to_unlock > 0)
+ if (blocks_to_unlock > 0 && time_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%lu block(s) and %s to unlock)") % blocks_to_unlock % get_human_readable_timespan(time_to_unlock)).str();
+ else if (blocks_to_unlock > 0)
unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
+ else if (time_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%s to unlock)") % get_human_readable_timespan(time_to_unlock)).str();
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account, false)) << ", "
<< tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account, false);
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
if (!detailed || balance_per_subaddress.empty())
return true;
success_msg_writer() << tr("Balance per address:");
@@ -8267,6 +8345,11 @@ static std::string get_human_readable_timespan(std::chrono::seconds seconds)
return sw::tr("a long time");
}
//----------------------------------------------------------------------------------------------------
+static std::string get_human_readable_timespan(uint64_t seconds)
+{
+ return get_human_readable_timespan(std::chrono::seconds(seconds));
+}
+//----------------------------------------------------------------------------------------------------
// mutates local_args as it parses and consumes arguments
bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vector<transfer_view>& transfers)
{
@@ -10351,6 +10434,14 @@ bool simple_wallet::user_confirms(const std::string &question)
return !std::cin.eof() && command_line::is_yes(answer);
}
+bool simple_wallet::user_confirms_auto_config()
+{
+ message_writer(console_color_red, true) << tr("WARNING: Using MMS auto-config mechanisms is not trustless");
+ message_writer() << tr("A malicious auto-config manager could send you info about own wallets instead of other signers' info");
+ message_writer() << tr("If in doubt do not use auto-config or at least compare configs using the \"mms config_checksum\" command");
+ return user_confirms("Accept the risks and continue?");
+}
+
bool simple_wallet::get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound)
{
bool valid = false;
@@ -10503,7 +10594,7 @@ void simple_wallet::show_message(const mms::message &m)
case mms::message_type::additional_key_set:
case mms::message_type::note:
display_content = true;
- ms.get_sanitized_message_text(m, sanitized_text);
+ sanitized_text = mms::message_store::get_sanitized_text(m.content, 1000);
break;
default:
display_content = false;
@@ -10852,6 +10943,11 @@ void simple_wallet::mms_next(const std::vector<std::string> &args)
{
break;
}
+ if (!user_confirms_auto_config())
+ {
+ message_writer() << tr("You can use the \"mms delete\" command to delete any unwanted message");
+ break;
+ }
}
ms.process_signer_config(state, m.content);
ms.stop_auto_config();
@@ -11178,6 +11274,18 @@ void simple_wallet::mms_start_auto_config(const std::vector<std::string> &args)
list_signers(ms.get_all_signers());
}
+void simple_wallet::mms_config_checksum(const std::vector<std::string> &args)
+{
+ if (args.size() != 0)
+ {
+ fail_msg_writer() << tr("Usage: mms config_checksum");
+ return;
+ }
+ mms::message_store& ms = m_wallet->get_message_store();
+ LOCK_IDLE_SCOPE();
+ message_writer() << ms.get_config_checksum();
+}
+
void simple_wallet::mms_stop_auto_config(const std::vector<std::string> &args)
{
if (args.size() != 0)
@@ -11208,6 +11316,10 @@ void simple_wallet::mms_auto_config(const std::vector<std::string> &args)
fail_msg_writer() << tr("Invalid auto-config token");
return;
}
+ if (!user_confirms_auto_config())
+ {
+ return;
+ }
mms::authorized_signer me = ms.get_signer(0);
if (me.auto_config_running)
{
@@ -11320,6 +11432,10 @@ bool simple_wallet::mms(const std::vector<std::string> &args)
{
mms_start_auto_config(mms_args);
}
+ else if (sub_command == "config_checksum")
+ {
+ mms_config_checksum(mms_args);
+ }
else if (sub_command == "stop_auto_config")
{
mms_stop_auto_config(mms_args);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 59818b303..5154ff1ef 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -53,7 +53,7 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.simplewallet"
// Hardcode Monero's donation address (see #1447)
-constexpr const char MONERO_DONATION_ADDR[] = "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A";
+constexpr const char MONERO_DONATION_ADDR[] = "888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H";
/*!
* \namespace cryptonote
@@ -258,6 +258,7 @@ namespace cryptonote
bool rpc_payment_info(const std::vector<std::string> &args);
bool start_mining_for_rpc(const std::vector<std::string> &args);
bool stop_mining_for_rpc(const std::vector<std::string> &args);
+ bool show_qr_code(const std::vector<std::string> &args);
bool net_stats(const std::vector<std::string>& args);
bool public_nodes(const std::vector<std::string>& args);
bool welcome(const std::vector<std::string>& args);
@@ -342,7 +343,7 @@ namespace cryptonote
//----------------- i_wallet2_callback ---------------------
virtual void on_new_block(uint64_t height, const cryptonote::block& block);
- virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time);
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time);
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index);
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index);
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx);
@@ -478,6 +479,7 @@ namespace cryptonote
void ask_send_all_ready_messages();
void check_for_messages();
bool user_confirms(const std::string &question);
+ bool user_confirms_auto_config();
bool get_message_from_arg(const std::string &arg, mms::message &m);
bool get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound);
@@ -498,6 +500,7 @@ namespace cryptonote
void mms_help(const std::vector<std::string> &args);
void mms_send_signer_config(const std::vector<std::string> &args);
void mms_start_auto_config(const std::vector<std::string> &args);
+ void mms_config_checksum(const std::vector<std::string> &args);
void mms_stop_auto_config(const std::vector<std::string> &args);
void mms_auto_config(const std::vector<std::string> &args);
};
diff --git a/src/version.cpp.in b/src/version.cpp.in
index ccb88f1fe..1e720537a 100644
--- a/src/version.cpp.in
+++ b/src/version.cpp.in
@@ -1,6 +1,6 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
-#define DEF_MONERO_VERSION "0.15.0.0"
-#define DEF_MONERO_RELEASE_NAME "Carbon Chamaeleon"
+#define DEF_MONERO_VERSION "0.16.0.0"
+#define DEF_MONERO_RELEASE_NAME "Nitrogen Nebula"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index a0a166a93..bf238ae37 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/wallet/api/CMakeLists.txt b/src/wallet/api/CMakeLists.txt
index 3376ec70e..30eb4ce03 100644
--- a/src/wallet/api/CMakeLists.txt
+++ b/src/wallet/api/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index 005ddf7ee..f69a69ca3 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/address_book.h b/src/wallet/api/address_book.h
index 92e6eaa17..f287969f3 100644
--- a/src/wallet/api/address_book.h
+++ b/src/wallet/api/address_book.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
index 52510164a..24f6d37db 100644
--- a/src/wallet/api/pending_transaction.cpp
+++ b/src/wallet/api/pending_transaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h
index 92801d77d..bd0ca80a6 100644
--- a/src/wallet/api/pending_transaction.h
+++ b/src/wallet/api/pending_transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/subaddress.cpp b/src/wallet/api/subaddress.cpp
index 8a1d34864..227bb343d 100644
--- a/src/wallet/api/subaddress.cpp
+++ b/src/wallet/api/subaddress.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/subaddress.h b/src/wallet/api/subaddress.h
index 87585ec16..18c9ed59e 100644
--- a/src/wallet/api/subaddress.h
+++ b/src/wallet/api/subaddress.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/subaddress_account.cpp b/src/wallet/api/subaddress_account.cpp
index eaaddc11f..5e502ed5b 100644
--- a/src/wallet/api/subaddress_account.cpp
+++ b/src/wallet/api/subaddress_account.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/subaddress_account.h b/src/wallet/api/subaddress_account.h
index 358e446d4..1318d4da5 100644
--- a/src/wallet/api/subaddress_account.h
+++ b/src/wallet/api/subaddress_account.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp
index ad7029a3c..bcb300889 100644
--- a/src/wallet/api/transaction_history.cpp
+++ b/src/wallet/api/transaction_history.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h
index 67fe1989d..8f3805788 100644
--- a/src/wallet/api/transaction_history.h
+++ b/src/wallet/api/transaction_history.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp
index 21573c6f6..5ae3a6937 100644
--- a/src/wallet/api/transaction_info.cpp
+++ b/src/wallet/api/transaction_info.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h
index d5c8f31cf..73bb7689d 100644
--- a/src/wallet/api/transaction_info.h
+++ b/src/wallet/api/transaction_info.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp
index c2c04cbc3..fb96674a7 100644
--- a/src/wallet/api/unsigned_transaction.cpp
+++ b/src/wallet/api/unsigned_transaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/unsigned_transaction.h b/src/wallet/api/unsigned_transaction.h
index f1af80fa1..81fc098ff 100644
--- a/src/wallet/api/unsigned_transaction.h
+++ b/src/wallet/api/unsigned_transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/utils.cpp b/src/wallet/api/utils.cpp
index 24252868a..34debee9d 100644
--- a/src/wallet/api/utils.cpp
+++ b/src/wallet/api/utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index d89261c64..66e248427 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -157,7 +157,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time)
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time)
{
std::string tx_hash = epee::string_tools::pod_to_hex(txid);
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 66eeb0e73..43d85b704 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index 9c3df8988..e2f96a069 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 8d7541cea..69d17eb02 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 0595b8327..ca8e9ada2 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp
index 1bd462ef5..fb07b42f0 100644
--- a/src/wallet/message_store.cpp
+++ b/src/wallet/message_store.cpp
@@ -39,6 +39,7 @@
#include "serialization/binary_utils.h"
#include "common/base58.h"
#include "common/util.h"
+#include "common/utf8.h"
#include "string_tools.h"
@@ -129,18 +130,18 @@ void message_store::set_signer(const multisig_wallet_state &state,
authorized_signer &m = m_signers[index];
if (label)
{
- m.label = label.get();
+ m.label = get_sanitized_text(label.get(), 50);
}
if (transport_address)
{
- m.transport_address = transport_address.get();
+ m.transport_address = get_sanitized_text(transport_address.get(), 200);
}
if (monero_address)
{
m.monero_address_known = true;
m.monero_address = monero_address.get();
}
- // Save to minimize the chance to loose that info (at least while in beta)
+ // Save to minimize the chance to loose that info
save(state);
}
@@ -202,6 +203,13 @@ void message_store::unpack_signer_config(const multisig_wallet_state &state, con
}
uint32_t num_signers = (uint32_t)signers.size();
THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + std::to_string(num_signers));
+ for (uint32_t i = 0; i < num_signers; ++i)
+ {
+ authorized_signer &m = signers[i];
+ m.label = get_sanitized_text(m.label, 50);
+ m.transport_address = get_sanitized_text(m.transport_address, 200);
+ m.auto_config_token = get_sanitized_text(m.auto_config_token, 20);
+ }
}
void message_store::process_signer_config(const multisig_wallet_state &state, const std::string &signer_config)
@@ -242,10 +250,10 @@ void message_store::process_signer_config(const multisig_wallet_state &state, co
}
}
authorized_signer &modify = m_signers[take_index];
- modify.label = m.label; // ALWAYS set label, see comments above
+ modify.label = get_sanitized_text(m.label, 50); // ALWAYS set label, see comments above
if (!modify.me)
{
- modify.transport_address = m.transport_address;
+ modify.transport_address = get_sanitized_text(m.transport_address, 200);
modify.monero_address_known = m.monero_address_known;
if (m.monero_address_known)
{
@@ -392,6 +400,45 @@ void message_store::process_auto_config_data_message(uint32_t id)
signer.auto_config_running = false;
}
+void add_hash(crypto::hash &sum, const crypto::hash &summand)
+{
+ for (uint32_t i = 0; i < crypto::HASH_SIZE; ++i)
+ {
+ uint32_t x = (uint32_t)sum.data[i];
+ uint32_t y = (uint32_t)summand.data[i];
+ sum.data[i] = (char)((x + y) % 256);
+ }
+}
+
+// Calculate a checksum that allows signers to make sure they work with an identical signer config
+// by exchanging and comparing checksums out-of-band i.e. not using the MMS;
+// Because different signers have a different order of signers in the config work with "adding"
+// individual hashes because that operation is commutative
+std::string message_store::get_config_checksum() const
+{
+ crypto::hash sum = crypto::null_hash;
+ uint32_t num = SWAP32LE(m_num_authorized_signers);
+ add_hash(sum, crypto::cn_fast_hash(&num, sizeof(num)));
+ num = SWAP32LE(m_num_required_signers);
+ add_hash(sum, crypto::cn_fast_hash(&num, sizeof(num)));
+ for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
+ {
+ const authorized_signer &m = m_signers[i];
+ add_hash(sum, crypto::cn_fast_hash(m.transport_address.data(), m.transport_address.size()));
+ if (m.monero_address_known)
+ {
+ add_hash(sum, crypto::cn_fast_hash(&m.monero_address.m_spend_public_key, sizeof(m.monero_address.m_spend_public_key)));
+ add_hash(sum, crypto::cn_fast_hash(&m.monero_address.m_view_public_key, sizeof(m.monero_address.m_view_public_key)));
+ }
+ }
+ std::string checksum_bytes;
+ checksum_bytes += sum.data[0];
+ checksum_bytes += sum.data[1];
+ checksum_bytes += sum.data[2];
+ checksum_bytes += sum.data[3];
+ return epee::string_tools::buff_to_hex_nodelimer(checksum_bytes);
+}
+
void message_store::stop_auto_config()
{
for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
@@ -661,32 +708,38 @@ void message_store::delete_all_messages()
m_messages.clear();
}
-// Make a message text, which is "attacker controlled data", reasonably safe to display
+// Make a text, which is "attacker controlled data", reasonably safe to display
// This is mostly geared towards the safe display of notes sent by "mms note" with a "mms show" command
-void message_store::get_sanitized_message_text(const message &m, std::string &sanitized_text) const
+std::string message_store::get_sanitized_text(const std::string &text, size_t max_length)
{
- sanitized_text.clear();
-
// Restrict the size to fend of DOS-style attacks with heaps of data
- size_t length = std::min(m.content.length(), (size_t)1000);
+ size_t length = std::min(text.length(), max_length);
+ std::string sanitized_text = text.substr(0, length);
- for (size_t i = 0; i < length; ++i)
+ try
{
- char c = m.content[i];
- if ((int)c < 32)
+ sanitized_text = tools::utf8canonical(sanitized_text, [](wint_t c)
{
- // Strip out any controls, especially ESC for getting rid of potentially dangerous
- // ANSI escape sequences that a console window might interpret
- c = ' ';
- }
- else if ((c == '<') || (c == '>'))
- {
- // Make XML or HTML impossible that e.g. might contain scripts that Qt might execute
- // when displayed in the GUI wallet
- c = ' ';
- }
- sanitized_text += c;
+ if ((c < 0x20) || (c == 0x7f) || (c >= 0x80 && c <= 0x9f))
+ {
+ // Strip out any controls, especially ESC for getting rid of potentially dangerous
+ // ANSI escape sequences that a console window might interpret
+ c = '?';
+ }
+ else if ((c == '<') || (c == '>'))
+ {
+ // Make XML or HTML impossible that e.g. might contain scripts that Qt might execute
+ // when displayed in the GUI wallet
+ c = '?';
+ }
+ return c;
+ });
+ }
+ catch (const std::exception &e)
+ {
+ sanitized_text = "(Illegal UTF-8 string)";
}
+ return sanitized_text;
}
void message_store::write_to_file(const multisig_wallet_state &state, const std::string &filename)
@@ -724,7 +777,7 @@ void message_store::read_from_file(const multisig_wallet_state &state, const std
{
// Simply do nothing if the file is not there; allows e.g. easy recovery
// from problems with the MMS by deleting the file
- MERROR("No message store file found: " << filename);
+ MINFO("No message store file found: " << filename);
return;
}
diff --git a/src/wallet/message_store.h b/src/wallet/message_store.h
index d40daf186..9055fd776 100644
--- a/src/wallet/message_store.h
+++ b/src/wallet/message_store.h
@@ -242,6 +242,7 @@ namespace mms
size_t add_auto_config_data_message(const multisig_wallet_state &state,
const std::string &auto_config_token);
void process_auto_config_data_message(uint32_t id);
+ std::string get_config_checksum() const;
void stop_auto_config();
// Process data just created by "me" i.e. the own local wallet, e.g. as the result of a "prepare_multisig" command
@@ -275,7 +276,7 @@ namespace mms
void set_message_processed_or_sent(uint32_t id);
void delete_message(uint32_t id);
void delete_all_messages();
- void get_sanitized_message_text(const message &m, std::string &sanitized_text) const;
+ static std::string get_sanitized_text(const std::string &text, size_t max_length);
void send_message(const multisig_wallet_state &state, uint32_t id);
bool check_for_messages(const multisig_wallet_state &state, std::vector<message> &messages);
diff --git a/src/wallet/message_transporter.h b/src/wallet/message_transporter.h
index 84a2e9bae..557833f2c 100644
--- a/src/wallet/message_transporter.h
+++ b/src/wallet/message_transporter.h
@@ -31,7 +31,6 @@
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "cryptonote_basic/account_boost_serialization.h"
-#include "cryptonote_basic/cryptonote_basic.h"
#include "net/http_server_impl_base.h"
#include "net/http_client.h"
#include "net/abstract_http_client.h"
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index 873c2ee51..95b8ce8bb 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index b053659e9..500ba81d4 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 476248d18..abc6981a0 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -947,7 +947,7 @@ uint32_t get_subaddress_clamped_sum(uint32_t idx, uint32_t extra)
static void setup_shim(hw::wallet_shim * shim, tools::wallet2 * wallet)
{
- shim->get_tx_pub_key_from_received_outs = boost::bind(&tools::wallet2::get_tx_pub_key_from_received_outs, wallet, _1);
+ shim->get_tx_pub_key_from_received_outs = std::bind(&tools::wallet2::get_tx_pub_key_from_received_outs, wallet, std::placeholders::_1);
}
bool get_pruned_tx(const cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry &entry, cryptonote::transaction &tx, crypto::hash &tx_hash)
@@ -1523,6 +1523,18 @@ void wallet2::add_subaddress(uint32_t index_major, const std::string& label)
m_subaddress_labels[index_major][index_minor] = label;
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::should_expand(const cryptonote::subaddress_index &index) const
+{
+ const uint32_t last_major = m_subaddress_labels.size() - 1 > (std::numeric_limits<uint32_t>::max() - m_subaddress_lookahead_major) ? std::numeric_limits<uint32_t>::max() : (m_subaddress_labels.size() + m_subaddress_lookahead_major - 1);
+ if (index.major > last_major)
+ return false;
+ const size_t nsub = index.major < m_subaddress_labels.size() ? m_subaddress_labels[index.major].size() : 0;
+ const uint32_t last_minor = nsub - 1 > (std::numeric_limits<uint32_t>::max() - m_subaddress_lookahead_minor) ? std::numeric_limits<uint32_t>::max() : (nsub + m_subaddress_lookahead_minor - 1);
+ if (index.minor > last_minor)
+ return false;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
{
hw::device &hwdev = m_account.get_device();
@@ -1855,6 +1867,20 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
}
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::spends_one_of_ours(const cryptonote::transaction &tx) const
+{
+ for (const auto &in: tx.vin)
+ {
+ if (in.type() != typeid(cryptonote::txin_to_key))
+ continue;
+ const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(in);
+ auto it = m_key_images.find(in_to_key.k_image);
+ if (it != m_key_images.end())
+ return true;
+ }
+ return false;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
PERF_TIMER(process_new_transaction);
@@ -2108,7 +2134,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
- if (tx_scan_info[o].received->index.major < m_subaddress_labels.size() && tx_scan_info[o].received->index.minor < m_subaddress_labels[tx_scan_info[o].received->index.major].size())
+ if (should_expand(tx_scan_info[o].received->index))
expand_subaddresses(tx_scan_info[o].received->index);
if (tx.vout[o].amount == 0)
{
@@ -2141,7 +2167,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (0 != m_callback)
- m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, td.m_tx.unlock_time);
+ m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time);
}
total_received_1 += amount;
notify = true;
@@ -2187,7 +2213,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
- if (tx_scan_info[o].received->index.major < m_subaddress_labels.size() && tx_scan_info[o].received->index.minor < m_subaddress_labels[tx_scan_info[o].received->index.major].size())
+ if (should_expand(tx_scan_info[o].received->index))
expand_subaddresses(tx_scan_info[o].received->index);
if (tx.vout[o].amount == 0)
{
@@ -2218,7 +2244,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (0 != m_callback)
- m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, td.m_tx.unlock_time);
+ m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time);
}
total_received_1 += extra_amount;
notify = true;
@@ -3978,13 +4004,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
// Load keys from buffer
boost::optional<crypto::chacha_key> keys_to_encrypt;
- try {
- r = wallet2::load_keys_buf(keys_file_buf, password, keys_to_encrypt);
- } catch (const std::exception& e) {
- std::size_t found = string(e.what()).find("failed to deserialize keys buffer");
- THROW_WALLET_EXCEPTION_IF(found != std::string::npos, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
- throw e;
- }
+ r = wallet2::load_keys_buf(keys_file_buf, password, keys_to_encrypt);
// Rewrite with encrypted keys if unencrypted, ignore errors
if (r && keys_to_encrypt != boost::none)
@@ -4329,9 +4349,24 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
if (r)
{
+ // Decrypt keys, using one of two possible methods
if (encrypted_secret_keys)
{
+ // First try the updated method
m_account.decrypt_keys(key);
+ load_info.is_legacy_key_encryption = false;
+
+ // Test address construction to see if decryption succeeded
+ const cryptonote::account_keys &keys = m_account.get_keys();
+ hw::device &hwdev = m_account.get_device();
+ if (!hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key) || !hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key))
+ {
+ // Updated method failed; try the legacy method
+ // Note that we must first encrypt the keys again with the same IV
+ m_account.encrypt_keys_same_iv(key);
+ m_account.decrypt_legacy(key);
+ load_info.is_legacy_key_encryption = true;
+ }
}
else
{
@@ -4848,6 +4883,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
std::vector<crypto::secret_key> multisig_keys;
rct::key spend_pkey = rct::identity();
rct::key spend_skey;
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(&spend_skey, sizeof(spend_skey));});
std::vector<crypto::public_key> multisig_signers;
// decrypt keys
@@ -5493,13 +5529,12 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t);
bool r = invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t);
- if(!r) {
+ if(!r || resp_t.status != CORE_RPC_STATUS_OK) {
if(version)
*version = 0;
return false;
}
- if (resp_t.status == CORE_RPC_STATUS_OK)
- m_rpc_version = resp_t.version;
+ m_rpc_version = resp_t.version;
}
if (version)
*version = m_rpc_version;
@@ -5535,6 +5570,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{
clear();
prepare_file_names(wallet_);
+ MINFO("Keys file: " << m_keys_file);
// determine if loading from file system or string buffer
bool use_fs = !wallet_.empty();
@@ -5912,18 +5948,22 @@ uint64_t wallet2::balance(uint32_t index_major, bool strict) const
return amount;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock) const
+uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
{
uint64_t amount = 0;
if (blocks_to_unlock)
*blocks_to_unlock = 0;
+ if (time_to_unlock)
+ *time_to_unlock = 0;
if(m_light_wallet)
return m_light_wallet_balance;
for (const auto& i : unlocked_balance_per_subaddress(index_major, strict))
{
amount += i.second.first;
- if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
- *blocks_to_unlock = i.second.second;
+ if (blocks_to_unlock && i.second.second.first > *blocks_to_unlock)
+ *blocks_to_unlock = i.second.second.first;
+ if (time_to_unlock && i.second.second.second > *time_to_unlock)
+ *time_to_unlock = i.second.second.second;
}
return amount;
}
@@ -5960,35 +6000,40 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
return amount_per_subaddr;
}
//----------------------------------------------------------------------------------------------------
-std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
+std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
{
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr;
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> amount_per_subaddr;
const uint64_t blockchain_height = get_blockchain_current_height();
+ const uint64_t now = time(NULL);
for(const transfer_details& td: m_transfers)
{
if(td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
{
- uint64_t amount = 0, blocks_to_unlock = 0;
+ uint64_t amount = 0, blocks_to_unlock = 0, time_to_unlock = 0;
if (is_transfer_unlocked(td))
{
amount = td.amount();
blocks_to_unlock = 0;
+ time_to_unlock = 0;
}
else
{
uint64_t unlock_height = td.m_block_height + std::max<uint64_t>(CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);
if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > unlock_height)
unlock_height = td.m_tx.unlock_time;
+ uint64_t unlock_time = td.m_tx.unlock_time >= CRYPTONOTE_MAX_BLOCK_NUMBER ? td.m_tx.unlock_time : 0;
blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 0;
+ time_to_unlock = unlock_time > now ? unlock_time - now : 0;
amount = 0;
}
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
- amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, blocks_to_unlock);
+ amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, std::make_pair(blocks_to_unlock, time_to_unlock));
else
{
found->second.first += amount;
- found->second.second = std::max(found->second.second, blocks_to_unlock);
+ found->second.second.first = std::max(found->second.second.first, blocks_to_unlock);
+ found->second.second.second = std::max(found->second.second.second, time_to_unlock);
}
}
}
@@ -6003,17 +6048,21 @@ uint64_t wallet2::balance_all(bool strict) const
return r;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock) const
+uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
{
uint64_t r = 0;
if (blocks_to_unlock)
*blocks_to_unlock = 0;
+ if (time_to_unlock)
+ *time_to_unlock = 0;
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
{
- uint64_t local_blocks_to_unlock;
- r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
+ uint64_t local_blocks_to_unlock, local_time_to_unlock;
+ r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL, time_to_unlock ? &local_time_to_unlock : NULL);
if (blocks_to_unlock)
*blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
+ if (time_to_unlock)
+ *time_to_unlock = std::max(*time_to_unlock, local_time_to_unlock);
}
return r;
}
@@ -6492,7 +6541,7 @@ void wallet2::commit_tx(pending_tx& ptx)
// tx generated, get rid of used k values
for (size_t idx: ptx.selected_transfers)
- m_transfers[idx].m_multisig_k.clear();
+ memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
//fee includes dust if dust policy specified it.
LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
@@ -6934,13 +6983,13 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs)
// txes generated, get rid of used k values
for (size_t n = 0; n < txs.m_ptx.size(); ++n)
for (size_t idx: txs.m_ptx[n].construction_data.selected_transfers)
- m_transfers[idx].m_multisig_k.clear();
+ memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
// zero out some data we don't want to share
for (auto &ptx: txs.m_ptx)
{
for (auto &e: ptx.construction_data.sources)
- e.multisig_kLRki.k = rct::zero();
+ memwipe(&e.multisig_kLRki.k, sizeof(e.multisig_kLRki.k));
}
for (auto &ptx: txs.m_ptx)
@@ -7148,10 +7197,12 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
ptx.tx.rct_signatures = sig.sigs;
rct::keyV k;
+ rct::key skey = rct::zero();
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){ memwipe(k.data(), k.size() * sizeof(k[0])); memwipe(&skey, sizeof(skey)); });
+
for (size_t idx: sd.selected_transfers)
k.push_back(get_multisig_k(idx, sig.used_L));
- rct::key skey = rct::zero();
for (const auto &msk: get_account().get_multisig_keys())
{
crypto::public_key pmsk = get_multisig_signing_public_key(msk);
@@ -7199,7 +7250,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
// txes generated, get rid of used k values
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers)
- m_transfers[idx].m_multisig_k.clear();
+ memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
exported_txs.m_signers.insert(get_multisig_signer_public_key());
@@ -8997,7 +9048,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
continue;
}
- if (!is_spent(td2, false) && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
+ if (!is_spent(td2, false) && !td2.m_frozen && !td2.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
{
// update our picks if those outputs are less related than any we
// already found. If the same, don't update, and oldest suitable outputs
@@ -9652,7 +9703,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// throw if attempting a transaction with no money
THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination);
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false);
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false);
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, false);
if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
@@ -11390,7 +11441,7 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
}
}
- sig_str = std::string("OutProofV1");
+ sig_str = std::string("OutProofV2");
}
else
{
@@ -11426,7 +11477,7 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], boost::none, shared_secret[i], a, sig[i]);
}
}
- sig_str = std::string("InProofV1");
+ sig_str = std::string("InProofV2");
}
const size_t num_sigs = shared_secret.size();
@@ -11505,8 +11556,14 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received) const
{
+ // InProofV1, InProofV2, OutProofV1, OutProofV2
const bool is_out = sig_str.substr(0, 3) == "Out";
- const std::string header = is_out ? "OutProofV1" : "InProofV1";
+ const std::string header = is_out ? sig_str.substr(0,10) : sig_str.substr(0,9);
+ int version = 2; // InProofV2
+ if (is_out && sig_str.substr(8,2) == "V1") version = 1; // OutProofV1
+ else if (is_out) version = 2; // OutProofV2
+ else if (sig_str.substr(7,2) == "V1") version = 1; // InProofV1
+
const size_t header_len = header.size();
THROW_WALLET_EXCEPTION_IF(sig_str.size() < header_len || sig_str.substr(0, header_len) != header, error::wallet_internal_error,
"Signature header check error");
@@ -11553,27 +11610,27 @@ bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote
if (is_out)
{
good_signature[0] = is_subaddress ?
- crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], sig[0]) :
- crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], sig[0]);
+ crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], sig[0], version) :
+ crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], sig[0], version);
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
{
good_signature[i + 1] = is_subaddress ?
- crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, address.m_spend_public_key, shared_secret[i + 1], sig[i + 1]) :
- crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, boost::none, shared_secret[i + 1], sig[i + 1]);
+ crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, address.m_spend_public_key, shared_secret[i + 1], sig[i + 1], version) :
+ crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, boost::none, shared_secret[i + 1], sig[i + 1], version);
}
}
else
{
good_signature[0] = is_subaddress ?
- crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], sig[0]) :
- crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], sig[0]);
+ crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], sig[0], version) :
+ crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], sig[0], version);
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
{
good_signature[i + 1] = is_subaddress ?
- crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], address.m_spend_public_key, shared_secret[i + 1], sig[i + 1]) :
- crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], boost::none, shared_secret[i + 1], sig[i + 1]);
+ crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], address.m_spend_public_key, shared_secret[i + 1], sig[i + 1], version) :
+ crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], boost::none, shared_secret[i + 1], sig[i + 1], version);
}
}
@@ -11711,7 +11768,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
std::ostringstream oss;
boost::archive::portable_binary_oarchive ar(oss);
ar << proofs << subaddr_spendkeys;
- return "ReserveProofV1" + tools::base58::encode(oss.str());
+ return "ReserveProofV2" + tools::base58::encode(oss.str());
}
bool wallet2::check_reserve_proof(const cryptonote::account_public_address &address, const std::string &message, const std::string &sig_str, uint64_t &total, uint64_t &spent)
@@ -11720,12 +11777,18 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
THROW_WALLET_EXCEPTION_IF(!check_connection(&rpc_version), error::wallet_internal_error, "Failed to connect to daemon: " + get_daemon_address());
THROW_WALLET_EXCEPTION_IF(rpc_version < MAKE_CORE_RPC_VERSION(1, 0), error::wallet_internal_error, "Daemon RPC version is too old");
- static constexpr char header[] = "ReserveProofV1";
- THROW_WALLET_EXCEPTION_IF(!boost::string_ref{sig_str}.starts_with(header), error::wallet_internal_error,
+ static constexpr char header_v1[] = "ReserveProofV1";
+ static constexpr char header_v2[] = "ReserveProofV2"; // assumes same length as header_v1
+ THROW_WALLET_EXCEPTION_IF(!boost::string_ref{sig_str}.starts_with(header_v1) && !boost::string_ref{sig_str}.starts_with(header_v2), error::wallet_internal_error,
"Signature header check error");
+ int version = 2; // assume newest version
+ if (boost::string_ref{sig_str}.starts_with(header_v1))
+ version = 1;
+ else if (boost::string_ref{sig_str}.starts_with(header_v2))
+ version = 2;
std::string sig_decoded;
- THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(std::strlen(header)), sig_decoded), error::wallet_internal_error,
+ THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(std::strlen(header_v1)), sig_decoded), error::wallet_internal_error,
"Signature decoding error");
std::istringstream iss(sig_decoded);
@@ -11806,9 +11869,9 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
// check singature for shared secret
- ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, proof.shared_secret, proof.shared_secret_sig);
+ ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, proof.shared_secret, proof.shared_secret_sig, version);
if (!ok && additional_tx_pub_keys.size() == tx.vout.size())
- ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[proof.index_in_tx], boost::none, proof.shared_secret, proof.shared_secret_sig);
+ ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[proof.index_in_tx], boost::none, proof.shared_secret, proof.shared_secret_sig, version);
if (!ok)
return false;
@@ -12757,7 +12820,7 @@ process:
const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
- if (td.m_subaddr_index.major < m_subaddress_labels.size() && td.m_subaddr_index.minor < m_subaddress_labels[td.m_subaddr_index.major].size())
+ if (should_expand(td.m_subaddr_index))
expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
td.m_key_image_request = true;
@@ -12950,7 +13013,7 @@ cryptonote::blobdata wallet2::export_multisig()
{
transfer_details &td = m_transfers[n];
crypto::key_image ki;
- td.m_multisig_k.clear();
+ memwipe(td.m_multisig_k.data(), td.m_multisig_k.size() * sizeof(td.m_multisig_k[0]));
info[n].m_LR.clear();
info[n].m_partial_key_images.clear();
@@ -13059,6 +13122,7 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs)
CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources");
std::vector<std::vector<rct::key>> k;
+ auto wiper = epee::misc_utils::create_scope_leave_handler([&](){for (auto &v: k) memwipe(v.data(), v.size() * sizeof(v[0]));});
k.reserve(m_transfers.size());
for (const auto &td: m_transfers)
k.push_back(td.m_multisig_k);
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 7618e310c..1d26c6a00 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -131,7 +131,7 @@ private:
public:
// Full wallet callbacks
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
- virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time) {}
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) {}
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {}
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index) {}
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx) {}
@@ -219,6 +219,15 @@ private:
friend class wallet_keys_unlocker;
friend class wallet_device_callback;
public:
+ // Contains data on how keys were loaded, primarily for unit test purposes
+ struct load_info_t {
+ bool is_legacy_key_encryption;
+ };
+
+ const load_info_t &get_load_info() const {
+ return load_info;
+ }
+
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
enum RefreshType {
@@ -835,13 +844,13 @@ private:
// locked & unlocked balance of given or current subaddress account
uint64_t balance(uint32_t subaddr_index_major, bool strict) const;
- uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL) const;
+ uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
// locked & unlocked balance per subaddress of given or current subaddress account
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
// all locked & unlocked balances of all subaddress accounts
uint64_t balance_all(bool strict) const;
- uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL) const;
+ uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
template<typename T>
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
@@ -1407,6 +1416,8 @@ private:
static std::string get_default_daemon_address() { CRITICAL_REGION_LOCAL(default_daemon_address_lock); return default_daemon_address; }
private:
+ load_info_t load_info;
+
/*!
* \brief Stores wallet information to wallet file.
* \param keys_file_name Name of wallet file
@@ -1516,6 +1527,9 @@ private:
std::string get_client_signature() const;
void check_rpc_cost(const char *call, uint64_t post_call_credits, uint64_t pre_credits, double expected_cost);
+ bool should_expand(const cryptonote::subaddress_index &index) const;
+ bool spends_one_of_ours(const cryptonote::transaction &tx) const;
+
cryptonote::account_base m_account;
boost::optional<epee::net_utils::http::login> m_daemon_login;
std::string m_daemon_address;
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
index 350f016c7..55058bf4e 100644
--- a/src/wallet/wallet_args.cpp
+++ b/src/wallet/wallet_args.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet_args.h b/src/wallet/wallet_args.h
index 59529662f..4af1b58fe 100644
--- a/src/wallet/wallet_args.h
+++ b/src/wallet/wallet_args.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index 3e94e604a..e889ed7d1 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet_rpc_helpers.h b/src/wallet/wallet_rpc_helpers.h
index 4291a112d..35714db03 100644
--- a/src/wallet/wallet_rpc_helpers.h
+++ b/src/wallet/wallet_rpc_helpers.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet_rpc_payments.cpp b/src/wallet/wallet_rpc_payments.cpp
index 4f5364269..6527b1384 100644
--- a/src/wallet/wallet_rpc_payments.cpp
+++ b/src/wallet/wallet_rpc_payments.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019, The Monero Project
+// Copyright (c) 2018-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index db2e2344b..fcaaf7616 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -428,10 +428,10 @@ namespace tools
try
{
res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict);
- res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock);
+ res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock, &res.time_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock, &res.time_to_unlock);
res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images();
std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account;
- std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account;
+ std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>>> unlocked_balance_per_subaddress_per_account;
if (req.all_accounts)
{
for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
@@ -451,7 +451,7 @@ namespace tools
{
uint32_t account_index = p.first;
std::map<uint32_t, uint64_t> balance_per_subaddress = p.second;
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
std::set<uint32_t> address_indices;
if (!req.all_accounts && !req.address_indices.empty())
{
@@ -471,7 +471,8 @@ namespace tools
info.address = m_wallet->get_subaddress_as_str(index);
info.balance = balance_per_subaddress[i];
info.unlocked_balance = unlocked_balance_per_subaddress[i].first;
- info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second;
+ info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second.first;
+ info.time_to_unlock = unlocked_balance_per_subaddress[i].second.second;
info.label = m_wallet->get_subaddress_label(index);
info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index; });
res.per_subaddress.emplace_back(std::move(info));
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 89bf3a924..6e39eca1e 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index a212b79e6..ae861d177 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 17
+#define WALLET_RPC_VERSION_MINOR 18
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@@ -84,6 +84,7 @@ namespace wallet_rpc
std::string label;
uint64_t num_unspent_outputs;
uint64_t blocks_to_unlock;
+ uint64_t time_to_unlock;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
@@ -94,6 +95,7 @@ namespace wallet_rpc
KV_SERIALIZE(label)
KV_SERIALIZE(num_unspent_outputs)
KV_SERIALIZE(blocks_to_unlock)
+ KV_SERIALIZE(time_to_unlock)
END_KV_SERIALIZE_MAP()
};
@@ -104,6 +106,7 @@ namespace wallet_rpc
bool multisig_import_needed;
std::vector<per_subaddress_info> per_subaddress;
uint64_t blocks_to_unlock;
+ uint64_t time_to_unlock;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balance)
@@ -111,6 +114,7 @@ namespace wallet_rpc
KV_SERIALIZE(multisig_import_needed)
KV_SERIALIZE(per_subaddress)
KV_SERIALIZE(blocks_to_unlock)
+ KV_SERIALIZE(time_to_unlock)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 9434fbc3e..9b455af6a 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index afc69ee88..c601b93ed 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -28,6 +28,8 @@
#
# Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+set(MONERO_WALLET_CRYPTO_BENCH "auto" CACHE STRING "Select wallet crypto libraries for benchmarking")
+
# The docs say this only affects grouping in IDEs
set(folder "tests")
set(TEST_DATA_DIR "${CMAKE_CURRENT_LIST_DIR}/data")
@@ -118,6 +120,41 @@ add_test(
NAME hash-target
COMMAND hash-target-tests)
+#
+# Configure wallet crypto benchmark
+#
+if (${MONERO_WALLET_CRYPTO_BENCH} STREQUAL "auto")
+ set(MONERO_WALLET_CRYPTO_BENCH "cn")
+ monero_crypto_autodetect(AVAILABLE BEST)
+ if (DEFINED AVAILABLE)
+ list(APPEND MONERO_WALLET_CRYPTO_BENCH ${AVAILABLE})
+ endif ()
+ message("Wallet crypto bench is using ${MONERO_WALLET_CRYPTO_BENCH}")
+endif ()
+
+list(REMOVE_DUPLICATES MONERO_WALLET_CRYPTO_BENCH)
+list(REMOVE_ITEM MONERO_WALLET_CRYPTO_BENCH "cn") # always used for comparison
+set(MONERO_WALLET_CRYPTO_BENCH_NAMES "(cn)")
+foreach(BENCH IN LISTS MONERO_WALLET_CRYPTO_BENCH)
+ monero_crypto_valid(${BENCH} VALID)
+ if (NOT VALID)
+ message(FATAL_ERROR "Invalid MONERO_WALLET_CRYPTO_BENCH option ${BENCH}")
+ endif ()
+
+ monero_crypto_get_target(${BENCH} BENCH_LIBRARY)
+ list(APPEND BENCH_OBJECTS $<TARGET_OBJECTS:${BENCH_LIBRARY}>)
+
+ monero_crypto_get_namespace(${BENCH} BENCH_NAMESPACE)
+ set(MONERO_WALLET_CRYPTO_BENCH_NAMES "${MONERO_WALLET_CRYPTO_BENCH_NAMES}(${BENCH_NAMESPACE})")
+endforeach ()
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/benchmark.h.in" "${MONERO_GENERATED_HEADERS_DIR}/tests/benchmark.h")
+add_executable(monero-wallet-crypto-bench benchmark.cpp ${BENCH_OBJECTS})
+target_link_libraries(monero-wallet-crypto-bench cncrypto)
+
+add_test(NAME wallet-crypto-bench COMMAND monero-wallet-crypto-bench)
+
+
set(enabled_tests
core_tests
difficulty
diff --git a/tests/benchmark.cpp b/tests/benchmark.cpp
new file mode 100644
index 000000000..0461f4c11
--- /dev/null
+++ b/tests/benchmark.cpp
@@ -0,0 +1,437 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "tests/benchmark.h"
+
+#include <boost/fusion/adapted/std_tuple.hpp>
+#include <boost/fusion/algorithm/iteration/fold.hpp>
+#include <boost/preprocessor/seq/enum.hpp>
+#include <boost/preprocessor/seq/for_each.hpp>
+#include <boost/preprocessor/seq/seq.hpp>
+#include <boost/preprocessor/seq.hpp>
+#include <boost/preprocessor/stringize.hpp>
+#include <boost/spirit/include/karma_char.hpp>
+#include <boost/spirit/include/karma_format.hpp>
+#include <boost/spirit/include/karma_repeat.hpp>
+#include <boost/spirit/include/karma_right_alignment.hpp>
+#include <boost/spirit/include/karma_sequence.hpp>
+#include <boost/spirit/include/karma_string.hpp>
+#include <boost/spirit/include/karma_uint.hpp>
+#include <boost/spirit/include/qi_char.hpp>
+#include <boost/spirit/include/qi_list.hpp>
+#include <boost/spirit/include/qi_parse.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <chrono>
+#include <cstring>
+#include <functional>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "crypto/crypto.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "monero/crypto/amd64-64-24k.h"
+#include "monero/crypto/amd64-51-30k.h"
+
+#define CHECK(...) \
+ if(!( __VA_ARGS__ )) \
+ throw std::runtime_error{ \
+ "TEST FAILED (line " \
+ BOOST_PP_STRINGIZE( __LINE__ ) \
+ "): " \
+ BOOST_PP_STRINGIZE( __VA_ARGS__ ) \
+ }
+
+//! Define function that forwards arguments to `crypto::func`.
+#define FORWARD_FUNCTION(func) \
+ template<typename... T> \
+ static bool func (T&&... args) \
+ { \
+ return ::crypto:: func (std::forward<T>(args)...); \
+ }
+
+#define CRYPTO_FUNCTION(library, func) \
+ BOOST_PP_CAT(BOOST_PP_CAT(monero_crypto_, library), func)
+
+#define CRYPTO_BENCHMARK(r, _, library) \
+ struct library \
+ { \
+ static constexpr const char* name() noexcept { return BOOST_PP_STRINGIZE(library); } \
+ static bool generate_key_derivation(const ::crypto::public_key &tx_pub, const ::crypto::secret_key &view_sec, ::crypto::key_derivation &out) \
+ { \
+ return CRYPTO_FUNCTION(library, _generate_key_derivation) (out.data, tx_pub.data, view_sec.data) == 0; \
+ } \
+ static bool derive_subaddress_public_key(const ::crypto::public_key &spend_pub, const ::crypto::key_derivation &d, std::size_t index, ::crypto::public_key &out) \
+ { \
+ ::crypto::ec_scalar scalar; \
+ ::crypto::derivation_to_scalar(d, index, scalar); \
+ return CRYPTO_FUNCTION(library, _generate_subaddress_public_key) (out.data, spend_pub.data, scalar.data) == 0; \
+ } \
+ };
+
+
+namespace
+{
+ //! Default number of iterations for benchmark timing.
+ constexpr const unsigned default_iterations = 1000;
+
+ //! \return Byte compare two objects of `T`.
+ template<typename T>
+ bool compare(const T& lhs, const T& rhs) noexcept
+ {
+ static_assert(!epee::has_padding<T>(), "type might have padding");
+ return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(T)) == 0;
+ }
+
+ //! Benchmark default monero crypto library - a re-arranged ref10 implementation.
+ struct cn
+ {
+ static constexpr const char* name() noexcept { return "cn"; }
+ FORWARD_FUNCTION( generate_key_derivation );
+ FORWARD_FUNCTION( derive_subaddress_public_key );
+ };
+
+ // Define functions for every library except for `cn` which is the head library.
+ BOOST_PP_SEQ_FOR_EACH(CRYPTO_BENCHMARK, _, BOOST_PP_SEQ_TAIL(BENCHMARK_LIBRARIES));
+
+ // All enabled benchmark libraries
+ using enabled_libraries = std::tuple<BOOST_PP_SEQ_ENUM(BENCHMARK_LIBRARIES)>;
+
+
+ //! Callable that runs a benchmark against all enabled libraries
+ template<typename R>
+ struct run_benchmark
+ {
+ using result = R;
+
+ template<typename B>
+ result operator()(result out, const B benchmark) const
+ {
+ using inner_result = typename B::result;
+ out.push_back({boost::fusion::fold(enabled_libraries{}, inner_result{}, benchmark), benchmark.name()});
+ std::sort(out.back().first.begin(), out.back().first.end());
+ return out;
+ }
+ };
+
+ //! Run 0+ benchmarks against all enabled libraries
+ template<typename R, typename... B>
+ R run_benchmarks(B&&... benchmarks)
+ {
+ auto out = boost::fusion::fold(std::make_tuple(std::forward<B>(benchmarks)...), R{}, run_benchmark<R>{});
+ std::sort(out.begin(), out.end());
+ return out;
+ }
+
+ //! Run a suite of benchmarks - allows for comparison against a subset of benchmarks
+ template<typename S>
+ std::pair<typename S::result, std::string> run_suite(const S& suite)
+ {
+ return {suite(), suite.name()};
+ }
+
+ //! Arguments given to every crypto library being benchmarked.
+ struct bench_args
+ {
+ explicit bench_args(unsigned iterations)
+ : iterations(iterations), one(), two()
+ {
+ crypto::generate_keys(one.pub, one.sec, one.sec, false);
+ crypto::generate_keys(two.pub, two.sec, two.sec, false);
+ }
+
+ const unsigned iterations;
+ cryptonote::keypair one;
+ cryptonote::keypair two;
+ };
+
+ /*! Tests the ECDH step used for monero txes where the tx-pub is always
+ de-compressed into a table every time. */
+ struct tx_pub_standard
+ {
+ using result = std::vector<std::pair<std::chrono::steady_clock::duration, std::string>>;
+ static constexpr const char* name() noexcept { return "standard"; }
+
+ const bench_args args;
+
+ template<typename L>
+ result operator()(result out, const L library) const
+ {
+ crypto::key_derivation us;
+ crypto::key_derivation them;
+ CHECK(crypto::generate_key_derivation(args.one.pub, args.two.sec, them));
+ CHECK(library.generate_key_derivation(args.one.pub, args.two.sec, us));
+ CHECK(compare(us, them));
+
+ unsigned i = 0;
+ for (unsigned j = 0; j < 100; ++j)
+ i += library.generate_key_derivation(args.one.pub, args.two.sec, us);
+ CHECK(i == 100);
+
+ i = 0;
+ const auto start = std::chrono::steady_clock::now();
+ for (unsigned j = 0; j < args.iterations; ++j)
+ i += library.generate_key_derivation(args.one.pub, args.two.sec, us);
+ const auto end = std::chrono::steady_clock::now();
+ CHECK(i == args.iterations);
+ CHECK(compare(us, them));
+
+ out.push_back({end - start, library.name()});
+ return out;
+ }
+ };
+
+ //! Tests various possible optimizations for tx ECDH-step.
+ struct tx_pub_suite
+ {
+ using result = std::vector<std::pair<tx_pub_standard::result, std::string>>;
+ static constexpr const char* name() noexcept { return "generate_key_derivation step"; }
+
+ const bench_args args;
+
+ result operator()() const
+ {
+ return run_benchmarks<result>(tx_pub_standard{args});
+ }
+ };
+
+ /*! Tests the shared-secret to output-key step used for monero txes where
+ the users spend-public is always de-compressed. */
+ struct output_pub_standard
+ {
+ using result = std::vector<std::pair<std::chrono::steady_clock::duration, std::string>>;
+ static constexpr const char* name() noexcept { return "standard"; }
+
+ const bench_args args;
+
+ template<typename L>
+ result operator()(result out, const L library) const
+ {
+ crypto::key_derivation derived;
+ crypto::public_key us;
+ crypto::public_key them;
+ CHECK(crypto::generate_key_derivation(args.one.pub, args.two.sec, derived));
+ CHECK(library.derive_subaddress_public_key(args.two.pub, derived, 0, us));
+ CHECK(crypto::derive_subaddress_public_key(args.two.pub, derived, 0, them));
+ CHECK(compare(us, them));
+
+ unsigned i = 0;
+ for (unsigned j = 0; j < 100; ++j)
+ i += library.derive_subaddress_public_key(args.two.pub, derived, j, us);
+ CHECK(i == 100);
+
+ i = 0;
+ const auto start = std::chrono::steady_clock::now();
+ for (unsigned j = 0; j < args.iterations; ++j)
+ i += library.derive_subaddress_public_key(args.two.pub, derived, j, us);
+ const auto end = std::chrono::steady_clock::now();
+ CHECK(i == args.iterations);
+
+ out.push_back({end - start, library.name()});
+ return out;
+ }
+ };
+
+ //! Tests various possible optimizations for shared-secret to output-key step.
+ struct output_pub_suite
+ {
+ using result = std::vector<std::pair<output_pub_standard::result, std::string>>;
+ static constexpr const char* name() noexcept { return "derive_subaddress_public_key step"; }
+
+ const bench_args args;
+
+ result operator()() const
+ {
+ return run_benchmarks<result>(output_pub_standard{args});
+ }
+ };
+
+ struct tx_bench_args
+ {
+ const bench_args main;
+ unsigned outputs;
+ };
+
+ /*! Simulates "standard" tx scanning where a tx-pubkey is de-compressed into
+ a table and user spend-public is de-compressed, every time. */
+ struct tx_standard
+ {
+ using result = std::vector<std::pair<std::chrono::steady_clock::duration, std::string>>;
+ static constexpr const char* name() noexcept { return "standard"; }
+
+ const tx_bench_args args;
+
+ template<typename L>
+ result operator()(result out, const L library) const
+ {
+ crypto::key_derivation derived_us;
+ crypto::key_derivation derived_them;
+ crypto::public_key us;
+ crypto::public_key them;
+ CHECK(library.generate_key_derivation(args.main.one.pub, args.main.two.sec, derived_us));
+ CHECK(crypto::generate_key_derivation(args.main.one.pub, args.main.two.sec, derived_them));
+ CHECK(library.derive_subaddress_public_key(args.main.two.pub, derived_us, 0, us));
+ CHECK(crypto::derive_subaddress_public_key(args.main.two.pub, derived_them, 0, them));
+ CHECK(compare(us, them));
+
+ unsigned i = 0;
+ for (unsigned j = 0; j < 100; ++j)
+ {
+ i += library.generate_key_derivation(args.main.one.pub, args.main.two.sec, derived_us);
+ i += library.derive_subaddress_public_key(args.main.two.pub, derived_us, j, us);
+ }
+ CHECK(i == 200);
+
+ i = 0;
+ const auto start = std::chrono::steady_clock::now();
+ for (unsigned j = 0; j < args.main.iterations; ++j)
+ {
+ i += library.generate_key_derivation(args.main.one.pub, args.main.two.sec, derived_us);
+ for (unsigned k = 0; k < args.outputs; ++k)
+ i += library.derive_subaddress_public_key(args.main.two.pub, derived_us, k, us);
+ }
+ const auto end = std::chrono::steady_clock::now();
+ CHECK(i == args.main.iterations + args.main.iterations * args.outputs);
+
+ out.push_back({end - start, library.name()});
+ return out;
+ }
+ };
+
+ //! Tests various possible optimizations for tx scanning.
+ struct tx_suite
+ {
+ using result = std::vector<std::pair<output_pub_standard::result, std::string>>;
+ std::string name() const { return "Transactions with " + std::to_string(args.outputs) + " outputs"; }
+
+ const tx_bench_args args;
+
+ result operator()() const
+ {
+ return run_benchmarks<result>(tx_standard{args});
+
+ }
+ };
+
+ std::chrono::steady_clock::duration print(const tx_pub_standard::result& leaf, std::ostream& out, unsigned depth)
+ {
+ namespace karma = boost::spirit::karma;
+ const std::size_t align = leaf.empty() ?
+ 0 : std::to_string(leaf.back().first.count()).size();
+ const auto best = leaf.empty() ?
+ std::chrono::steady_clock::duration::max() : leaf.front().first;
+ for (auto const& entry : leaf)
+ {
+ out << karma::format(karma::repeat(depth ? depth - 1 : 0)["| "]) << '|';
+ out << karma::format((karma::right_align(std::min(20u - depth, 20u), '-')["> " << karma::string]), entry.second);
+ out << " => " << karma::format((karma::right_align(align)[karma::uint_]), entry.first.count());
+ out << " ns (+";
+ out << (double((entry.first - best).count()) / best.count()) * 100 << "%)" << std::endl;
+ }
+ out << karma::format(karma::repeat(depth ? depth - 1 : 0)["| "]) << std::endl;
+ return best;
+ }
+
+ template<typename T>
+ std::chrono::steady_clock::duration
+ print(const std::vector<std::pair<T, std::string>>& node, std::ostream& out, unsigned depth)
+ {
+ auto best = std::chrono::steady_clock::duration::max();
+ for (auto const& entry : node)
+ {
+ std::stringstream buffer{};
+ auto last = print(entry.first, buffer, depth + 1);
+ if (last != std::chrono::steady_clock::duration::max())
+ {
+ namespace karma = boost::spirit::karma;
+ best = std::min(best, last);
+ out << karma::format(karma::repeat(depth)["|-"]);
+ out << "+ " << entry.second << ' ';
+ out << last.count() << " ns (+";
+ out << (double((last - best).count()) / best.count()) * 100 << "%)" << std::endl;
+ out << buffer.str();
+ }
+ }
+ return best;
+ }
+} // anonymous namespace
+
+int main(int argc, char** argv)
+{
+ using results = std::vector<std::pair<tx_pub_suite::result, std::string>>;
+ try
+ {
+ unsigned iterations = default_iterations;
+ std::vector<unsigned> nums{};
+ if (2 <= argc) iterations = std::stoul(argv[1]);
+ if (3 <= argc)
+ {
+ namespace qi = boost::spirit::qi;
+ if (!qi::parse(argv[2], argv[2] + strlen(argv[2]), (qi::uint_ % ','), nums))
+ throw std::runtime_error{"bad tx outputs string"};
+ }
+ else
+ {
+ nums = {2, 4};
+ }
+ std::sort(nums.begin(), nums.end());
+ nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
+
+ std::cout << "Running benchmark using " << iterations << " iterations" << std::endl;
+
+ const bench_args args{iterations};
+
+ results val{};
+
+ std::cout << "Transaction Component Benchmarks" << std::endl;
+ std::cout << "--------------------------------" << std::endl;
+ val.push_back(run_suite(tx_pub_suite{args}));
+ val.push_back(run_suite(output_pub_suite{args}));
+ std::sort(val.begin(), val.end());
+ print(val, std::cout, 0);
+
+ val.clear();
+ std::cout << "Transaction Benchmarks" << std::endl;
+ std::cout << "----------------------" << std::endl;
+ for (const unsigned num : nums)
+ val.push_back(run_suite(tx_suite{{args, num}}));
+ std::sort(val.begin(), val.end());
+ print(val, std::cout, 0);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Error: " << e.what() << std::endl;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/tests/benchmark.h.in b/tests/benchmark.h.in
new file mode 100644
index 000000000..b13ea30b7
--- /dev/null
+++ b/tests/benchmark.h.in
@@ -0,0 +1,5 @@
+#pragma once
+
+// A Boost PP sequence
+#define BENCHMARK_LIBRARIES @MONERO_WALLET_CRYPTO_BENCH_NAMES@
+
diff --git a/tests/block_weight/block_weight.cpp b/tests/block_weight/block_weight.cpp
index f193133da..60606d53f 100644
--- a/tests/block_weight/block_weight.cpp
+++ b/tests/block_weight/block_weight.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/block_weight/block_weight.py b/tests/block_weight/block_weight.py
index b23da3d77..f396585a4 100755
--- a/tests/block_weight/block_weight.py
+++ b/tests/block_weight/block_weight.py
@@ -2,7 +2,7 @@
# Simulate a maximal block attack on the Monero network
# This uses the scheme proposed by ArticMine
# Written by Sarang Nother
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
from __future__ import print_function
import sys
import math
diff --git a/tests/core_proxy/CMakeLists.txt b/tests/core_proxy/CMakeLists.txt
index 9818d35d7..7896389f2 100644
--- a/tests/core_proxy/CMakeLists.txt
+++ b/tests/core_proxy/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp
index 9463d14ce..8095f03e3 100644
--- a/tests/core_proxy/core_proxy.cpp
+++ b/tests/core_proxy/core_proxy.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -47,7 +47,6 @@
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.inl"
#include "core_proxy.h"
-#include "version.h"
#if defined(WIN32)
#include <crtdbg.h>
diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h
index aad1bc962..4a41b5002 100644
--- a/tests/core_proxy/core_proxy.h
+++ b/tests/core_proxy/core_proxy.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt
index 42e76e613..ca9a09d82 100644
--- a/tests/core_tests/CMakeLists.txt
+++ b/tests/core_tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/core_tests/block_reward.cpp b/tests/core_tests/block_reward.cpp
index 17fc762ec..55eb517df 100644
--- a/tests/core_tests/block_reward.cpp
+++ b/tests/core_tests/block_reward.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/block_reward.h b/tests/core_tests/block_reward.h
index 6234bb9c5..ef62abc7f 100644
--- a/tests/core_tests/block_reward.h
+++ b/tests/core_tests/block_reward.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp
index 55312bc15..10b1b9af4 100644
--- a/tests/core_tests/block_validation.cpp
+++ b/tests/core_tests/block_validation.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/block_validation.h b/tests/core_tests/block_validation.h
index 2393e1b01..39eba0829 100644
--- a/tests/core_tests/block_validation.h
+++ b/tests/core_tests/block_validation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/bulletproofs.cpp b/tests/core_tests/bulletproofs.cpp
index 0a5b98605..04eeb9e01 100644
--- a/tests/core_tests/bulletproofs.cpp
+++ b/tests/core_tests/bulletproofs.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/bulletproofs.h b/tests/core_tests/bulletproofs.h
index 83f160d71..93fe2947f 100644
--- a/tests/core_tests/bulletproofs.h
+++ b/tests/core_tests/bulletproofs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chain_split_1.cpp b/tests/core_tests/chain_split_1.cpp
index c51accb67..640ccfcc6 100644
--- a/tests/core_tests/chain_split_1.cpp
+++ b/tests/core_tests/chain_split_1.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chain_split_1.h b/tests/core_tests/chain_split_1.h
index 503c3da19..59c7c4bd3 100644
--- a/tests/core_tests/chain_split_1.h
+++ b/tests/core_tests/chain_split_1.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chain_switch_1.cpp b/tests/core_tests/chain_switch_1.cpp
index 0554fd676..d0d04d1c9 100644
--- a/tests/core_tests/chain_switch_1.cpp
+++ b/tests/core_tests/chain_switch_1.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chain_switch_1.h b/tests/core_tests/chain_switch_1.h
index c084de262..c7ba83502 100644
--- a/tests/core_tests/chain_switch_1.h
+++ b/tests/core_tests/chain_switch_1.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp
index f935d4f64..f442a4977 100644
--- a/tests/core_tests/chaingen.cpp
+++ b/tests/core_tests/chaingen.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index 453ee923d..edaa9b20a 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -30,6 +30,7 @@
#pragma once
+#include <functional>
#include <vector>
#include <iostream>
#include <stdint.h>
@@ -856,10 +857,10 @@ inline bool do_replay_file(const std::string& filename)
}
#define REGISTER_CALLBACK(CB_NAME, CLBACK) \
- register_callback(CB_NAME, boost::bind(&CLBACK, this, _1, _2, _3));
+ register_callback(CB_NAME, std::bind(&CLBACK, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
#define REGISTER_CALLBACK_METHOD(CLASS, METHOD) \
- register_callback(#METHOD, boost::bind(&CLASS::METHOD, this, _1, _2, _3));
+ register_callback(#METHOD, std::bind(&CLASS::METHOD, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
#define MAKE_GENESIS_BLOCK(VEC_EVENTS, BLK_NAME, MINER_ACC, TS) \
test_generator generator; \
diff --git a/tests/core_tests/chaingen001.cpp b/tests/core_tests/chaingen001.cpp
index b313f4821..6d1741b06 100644
--- a/tests/core_tests/chaingen001.cpp
+++ b/tests/core_tests/chaingen001.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp
index 8a313140c..38382b95f 100644
--- a/tests/core_tests/chaingen_main.cpp
+++ b/tests/core_tests/chaingen_main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h
index cf20c725c..94eb23ce9 100644
--- a/tests/core_tests/chaingen_tests_list.h
+++ b/tests/core_tests/chaingen_tests_list.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/double_spend.cpp b/tests/core_tests/double_spend.cpp
index 4aa12c8e0..04a7a6921 100644
--- a/tests/core_tests/double_spend.cpp
+++ b/tests/core_tests/double_spend.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/double_spend.h b/tests/core_tests/double_spend.h
index 70d9f84b9..9f00348aa 100644
--- a/tests/core_tests/double_spend.h
+++ b/tests/core_tests/double_spend.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl
index 684c9c4de..22af95a37 100644
--- a/tests/core_tests/double_spend.inl
+++ b/tests/core_tests/double_spend.inl
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp
index 42df4aa3b..5cb5a7959 100644
--- a/tests/core_tests/integer_overflow.cpp
+++ b/tests/core_tests/integer_overflow.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/integer_overflow.h b/tests/core_tests/integer_overflow.h
index 75a60eb15..384178bbd 100644
--- a/tests/core_tests/integer_overflow.h
+++ b/tests/core_tests/integer_overflow.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp
index ba6e2d270..28d43e815 100644
--- a/tests/core_tests/multisig.cpp
+++ b/tests/core_tests/multisig.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/multisig.h b/tests/core_tests/multisig.h
index 10fe6ffe8..462c74f46 100644
--- a/tests/core_tests/multisig.h
+++ b/tests/core_tests/multisig.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp
index 23638f62d..6bf708855 100644
--- a/tests/core_tests/rct.cpp
+++ b/tests/core_tests/rct.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/rct.h b/tests/core_tests/rct.h
index 9433d4b02..0aaa93c94 100644
--- a/tests/core_tests/rct.h
+++ b/tests/core_tests/rct.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/ring_signature_1.cpp b/tests/core_tests/ring_signature_1.cpp
index eb5ee48ec..b4a7d8853 100644
--- a/tests/core_tests/ring_signature_1.cpp
+++ b/tests/core_tests/ring_signature_1.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/ring_signature_1.h b/tests/core_tests/ring_signature_1.h
index 256f5732b..10e0ab9ee 100644
--- a/tests/core_tests/ring_signature_1.h
+++ b/tests/core_tests/ring_signature_1.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp
index 14028b5be..d0b55dcf4 100644
--- a/tests/core_tests/transaction_tests.cpp
+++ b/tests/core_tests/transaction_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/transaction_tests.h b/tests/core_tests/transaction_tests.h
index eac2c3479..e74d48296 100644
--- a/tests/core_tests/transaction_tests.h
+++ b/tests/core_tests/transaction_tests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/tx_pool.cpp b/tests/core_tests/tx_pool.cpp
index b60dd00fc..1e496f3da 100644
--- a/tests/core_tests/tx_pool.cpp
+++ b/tests/core_tests/tx_pool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/tx_pool.h b/tests/core_tests/tx_pool.h
index 8a27e98f0..1fbdcadf1 100644
--- a/tests/core_tests/tx_pool.h
+++ b/tests/core_tests/tx_pool.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp
index acdfdc41b..244763988 100644
--- a/tests/core_tests/tx_validation.cpp
+++ b/tests/core_tests/tx_validation.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h
index 8d457cdb5..5f91f1291 100644
--- a/tests/core_tests/tx_validation.h
+++ b/tests/core_tests/tx_validation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/v2_tests.cpp b/tests/core_tests/v2_tests.cpp
index d00d9b6f4..8baf5eb0a 100644
--- a/tests/core_tests/v2_tests.cpp
+++ b/tests/core_tests/v2_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/core_tests/v2_tests.h b/tests/core_tests/v2_tests.h
index 71b0f0e83..23a6c43b6 100644
--- a/tests/core_tests/v2_tests.h
+++ b/tests/core_tests/v2_tests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/CMakeLists.txt b/tests/crypto/CMakeLists.txt
index 883efb3b0..dcf5d8fb0 100644
--- a/tests/crypto/CMakeLists.txt
+++ b/tests/crypto/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/crypto/cnv4-jit.c b/tests/crypto/cnv4-jit.c
index 0f11e4393..ac5bc0f52 100644
--- a/tests/crypto/cnv4-jit.c
+++ b/tests/crypto/cnv4-jit.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/crypto-ops-data.c b/tests/crypto/crypto-ops-data.c
index 63fedff07..0f187a3ea 100644
--- a/tests/crypto/crypto-ops-data.c
+++ b/tests/crypto/crypto-ops-data.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/crypto-ops.c b/tests/crypto/crypto-ops.c
index 9b1ccfcee..576b6e4b5 100644
--- a/tests/crypto/crypto-ops.c
+++ b/tests/crypto/crypto-ops.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/crypto-tests.h b/tests/crypto/crypto-tests.h
index be8d5a2e1..e833c0444 100644
--- a/tests/crypto/crypto-tests.h
+++ b/tests/crypto/crypto-tests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/crypto.cpp b/tests/crypto/crypto.cpp
index 160e0a23f..145ec1d86 100644
--- a/tests/crypto/crypto.cpp
+++ b/tests/crypto/crypto.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/hash.c b/tests/crypto/hash.c
index d65f13f11..680f2c4b4 100644
--- a/tests/crypto/hash.c
+++ b/tests/crypto/hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/main.cpp b/tests/crypto/main.cpp
index 3cdef4ce7..f804c45dc 100644
--- a/tests/crypto/main.cpp
+++ b/tests/crypto/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/crypto/random.c b/tests/crypto/random.c
index 7a17cbccc..eff3b9bbe 100644
--- a/tests/crypto/random.c
+++ b/tests/crypto/random.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/cryptolib.pl b/tests/cryptolib.pl
index d26ce601c..42604c782 100644
--- a/tests/cryptolib.pl
+++ b/tests/cryptolib.pl
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/cryptotest.pl b/tests/cryptotest.pl
index 57f6e2c5a..b5d4dd2df 100644
--- a/tests/cryptotest.pl
+++ b/tests/cryptotest.pl
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/daemon_tests/CMakeLists.txt b/tests/daemon_tests/CMakeLists.txt
index a32f26584..7735b5ecb 100644
--- a/tests/daemon_tests/CMakeLists.txt
+++ b/tests/daemon_tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/daemon_tests/transfers.cpp b/tests/daemon_tests/transfers.cpp
index e20e6b280..5afe93457 100644
--- a/tests/daemon_tests/transfers.cpp
+++ b/tests/daemon_tests/transfers.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/data/fuzz/tx-extra/TXEXTRA1 b/tests/data/fuzz/tx-extra/TXEXTRA1
new file mode 100644
index 000000000..08852abe3
--- /dev/null
+++ b/tests/data/fuzz/tx-extra/TXEXTRA1
Binary files differ
diff --git a/tests/data/fuzz/tx-extra/TXEXTRA2 b/tests/data/fuzz/tx-extra/TXEXTRA2
new file mode 100644
index 000000000..170301145
--- /dev/null
+++ b/tests/data/fuzz/tx-extra/TXEXTRA2
Binary files differ
diff --git a/tests/difficulty/CMakeLists.txt b/tests/difficulty/CMakeLists.txt
index c4f5a5dc0..c5c3bfb02 100644
--- a/tests/difficulty/CMakeLists.txt
+++ b/tests/difficulty/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/difficulty/difficulty.cpp b/tests/difficulty/difficulty.cpp
index 18f1d0030..aee17e9d5 100644
--- a/tests/difficulty/difficulty.cpp
+++ b/tests/difficulty/difficulty.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/difficulty/generate-data b/tests/difficulty/generate-data
index 3a9976e05..a566905fc 100755
--- a/tests/difficulty/generate-data
+++ b/tests/difficulty/generate-data
@@ -1,6 +1,6 @@
#!/usr/bin/python3
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/CMakeLists.txt b/tests/functional_tests/CMakeLists.txt
index 702ccc646..6972be55f 100644
--- a/tests/functional_tests/CMakeLists.txt
+++ b/tests/functional_tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/address_book.py b/tests/functional_tests/address_book.py
index f9ec217af..37a5915c9 100755
--- a/tests/functional_tests/address_book.py
+++ b/tests/functional_tests/address_book.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
#encoding=utf-8
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
@@ -145,7 +145,7 @@ class AddressBookTest():
res = wallet.get_address_book()
assert len(res.entries) == 1
e = res.entries[0]
- assert e.address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
+ assert e.address == '888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'
assert e.description == 'dev fund'
# UTF-8
@@ -173,7 +173,7 @@ class AddressBookTest():
# get them back
res = wallet.get_address_book([0])
assert len(res.entries) == 1
- assert res.entries[0].address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
+ assert res.entries[0].address == '888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'
assert res.entries[0].description == 'dev fund'
res = wallet.get_address_book([1])
assert len(res.entries) == 1
@@ -213,12 +213,12 @@ class AddressBookTest():
assert e.index == 1
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
assert e.description == u'えんしゅう'
- res = wallet.edit_address_book(1, address = '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A')
+ res = wallet.edit_address_book(1, address = '888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H')
res = wallet.get_address_book([1])
assert len(res.entries) == 1
e = res.entries[0]
assert e.index == 1
- assert e.address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
+ assert e.address == '888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'
assert e.description == u'えんしゅう'
ok = False
try: res = wallet.edit_address_book(1, address = '')
@@ -237,7 +237,7 @@ class AddressBookTest():
wallet.delete_address_book(0)
res = wallet.get_address_book([0]) # entries above the deleted one collapse one slot up
assert len(res.entries) == 1
- assert res.entries[0].address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
+ assert res.entries[0].address == '888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'
assert res.entries[0].description == u'えんしゅう'
wallet.delete_address_book(2)
wallet.delete_address_book(0)
diff --git a/tests/functional_tests/bans.py b/tests/functional_tests/bans.py
index e859e58c9..3e265a11e 100755
--- a/tests/functional_tests/bans.py
+++ b/tests/functional_tests/bans.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/cold_signing.py b/tests/functional_tests/cold_signing.py
index 698217436..35e00e105 100755
--- a/tests/functional_tests/cold_signing.py
+++ b/tests/functional_tests/cold_signing.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py
index 42d14e91a..5f2a3d077 100755
--- a/tests/functional_tests/functional_tests_rpc.py
+++ b/tests/functional_tests/functional_tests_rpc.py
@@ -34,8 +34,8 @@ try:
except:
tests = DEFAULT_TESTS
-N_MONERODS = 3
-N_WALLETS = 7
+N_MONERODS = 2
+N_WALLETS = 4
WALLET_DIRECTORY = builddir + "/functional-tests-directory"
DIFFICULTY = 10
@@ -43,17 +43,9 @@ monerod_base = [builddir + "/bin/monerod", "--regtest", "--fixed-difficulty", st
monerod_extra = [
[],
["--rpc-payment-address", "44SKxxLQw929wRF6BA9paQ1EWFshNnKhXM3qz6Mo3JGDE2YG3xyzVutMStEicxbQGRfrYvAAYxH6Fe8rnD56EaNwUiqhcwR", "--rpc-payment-difficulty", str(DIFFICULTY), "--rpc-payment-credits", "5000", "--data-dir", builddir + "/functional-tests-directory/monerod1"],
- ["--rpc-restricted-bind-port", "18482", "--data-dir", builddir + "/functional-tests-directory/monerod2"]
]
-wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--log-level", "1"]
+wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--daemon-port", "18180", "--log-level", "1"]
wallet_extra = [
- ["--daemon-port", "18180"],
- ["--daemon-port", "18180"],
- ["--daemon-port", "18180"],
- ["--daemon-port", "18180"],
- ["--daemon-port", "18182"],
- ["--daemon-port", "18182"],
- ["--daemon-port", "18182"]
]
command_lines = []
diff --git a/tests/functional_tests/get_output_distribution.py b/tests/functional_tests/get_output_distribution.py
index 077b094ba..24b6e9008 100755
--- a/tests/functional_tests/get_output_distribution.py
+++ b/tests/functional_tests/get_output_distribution.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/integrated_address.py b/tests/functional_tests/integrated_address.py
index 4e42261a6..c3b730de0 100755
--- a/tests/functional_tests/integrated_address.py
+++ b/tests/functional_tests/integrated_address.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/main.cpp b/tests/functional_tests/main.cpp
index c6869f755..8d140f721 100644
--- a/tests/functional_tests/main.cpp
+++ b/tests/functional_tests/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/functional_tests/make_test_signature.cc b/tests/functional_tests/make_test_signature.cc
index f31816841..07cc3eea6 100644
--- a/tests/functional_tests/make_test_signature.cc
+++ b/tests/functional_tests/make_test_signature.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/functional_tests/multisig.py b/tests/functional_tests/multisig.py
index e4e908aa1..0a58f469a 100755
--- a/tests/functional_tests/multisig.py
+++ b/tests/functional_tests/multisig.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/proofs.py b/tests/functional_tests/proofs.py
index 7beb3ec6e..e58d29f94 100755
--- a/tests/functional_tests/proofs.py
+++ b/tests/functional_tests/proofs.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
@@ -130,13 +130,13 @@ class ProofsTest():
sending_address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
receiving_address = '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW'
res = self.wallet[0].get_tx_proof(txid, sending_address, 'foo');
- assert res.signature.startswith('InProof');
+ assert res.signature.startswith('InProofV2');
signature0i = res.signature
res = self.wallet[0].get_tx_proof(txid, receiving_address, 'bar');
- assert res.signature.startswith('OutProof');
+ assert res.signature.startswith('OutProofV2');
signature0o = res.signature
res = self.wallet[1].get_tx_proof(txid, receiving_address, 'baz');
- assert res.signature.startswith('InProof');
+ assert res.signature.startswith('InProofV2');
signature1 = res.signature
res = self.wallet[0].check_tx_proof(txid, sending_address, 'foo', signature0i);
@@ -219,6 +219,23 @@ class ProofsTest():
except: ok = True
assert ok or not res.good
+
+ # Test bad cross-version verification
+ ok = False
+ try: res = self.wallet[0].check_tx_proof(txid, sending_address, 'foo', signature0i.replace('ProofV2','ProofV1'));
+ except: ok = True
+ assert ok or not res.good
+
+ ok = False
+ try: res = self.wallet[0].check_tx_proof(txid, receiving_address, 'bar', signature0o.replace('ProofV2','ProofV1'));
+ except: ok = True
+ assert ok or not res.good
+
+ ok = False
+ try: res = self.wallet[1].check_tx_proof(txid, receiving_address, 'baz', signature1.replace('ProofV2','ProofV1'));
+ except: ok = True
+ assert ok or not res.good
+
def check_spend_proof(self, txid):
daemon = Daemon()
@@ -270,7 +287,7 @@ class ProofsTest():
balance1 = res.balance
res = self.wallet[0].get_reserve_proof(all_ = True, message = 'foo')
- assert res.signature.startswith('ReserveProof')
+ assert res.signature.startswith('ReserveProofV2')
signature = res.signature
for i in range(2):
res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature)
@@ -287,9 +304,15 @@ class ProofsTest():
except: ok = True
assert ok or not res.good
+ # Test bad cross-version verification
+ ok = False
+ try: res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature.replace('ProofV2','ProofV1'))
+ except: ok = True
+ assert ok or not res.good
+
amount = int(balance0 / 10)
res = self.wallet[0].get_reserve_proof(all_ = False, amount = amount, message = 'foo')
- assert res.signature.startswith('ReserveProof')
+ assert res.signature.startswith('ReserveProofV2')
signature = res.signature
for i in range(2):
res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature)
@@ -306,6 +329,12 @@ class ProofsTest():
except: ok = True
assert ok or not res.good
+ # Test bad cross-version verification
+ ok = False
+ try: res = self.wallet[i].check_reserve_proof(address = address0, message = 'foo', signature = signature.replace('ProofV2','ProofV1'))
+ except: ok = True
+ assert ok or not res.good
+
ok = False
try: self.wallet[0].get_reserve_proof(all_ = False, amount = balance0 + 1, message = 'foo')
except: ok = True
diff --git a/tests/functional_tests/rpc_payment.py b/tests/functional_tests/rpc_payment.py
index 5f23c2022..d0f9c2913 100755
--- a/tests/functional_tests/rpc_payment.py
+++ b/tests/functional_tests/rpc_payment.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/sign_message.py b/tests/functional_tests/sign_message.py
index 9dd70f8bc..7ce2f2c18 100755
--- a/tests/functional_tests/sign_message.py
+++ b/tests/functional_tests/sign_message.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/speed.py b/tests/functional_tests/speed.py
index 71be785b8..c0c1d23c2 100755
--- a/tests/functional_tests/speed.py
+++ b/tests/functional_tests/speed.py
@@ -67,7 +67,7 @@ class SpeedTest():
destinations = []
for i in range(3):
- destinations.append({"amount":1,"address":'44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'})
+ destinations.append({"amount":1,"address":'888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'})
self._test_speed_generateblocks(daemon=daemon, blocks=70)
for i in range(1, 10):
@@ -89,7 +89,7 @@ class SpeedTest():
print('Test speed of transfer')
start = time.time()
- destinations = [{"amount":1,"address":'44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'}]
+ destinations = [{"amount":1,"address":'888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'}]
res = wallet.transfer_split(destinations)
print('generating tx took: ', time.time() - start, 'seconds')
diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp
index 218590a27..cec6825f5 100644
--- a/tests/functional_tests/transactions_flow_test.cpp
+++ b/tests/functional_tests/transactions_flow_test.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/functional_tests/transactions_flow_test.h b/tests/functional_tests/transactions_flow_test.h
index 530400df8..8e2dfd92c 100644
--- a/tests/functional_tests/transactions_flow_test.h
+++ b/tests/functional_tests/transactions_flow_test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/functional_tests/transactions_generation_from_blockchain.cpp b/tests/functional_tests/transactions_generation_from_blockchain.cpp
index b9c43e0e9..3ba401529 100644
--- a/tests/functional_tests/transactions_generation_from_blockchain.cpp
+++ b/tests/functional_tests/transactions_generation_from_blockchain.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/functional_tests/transactions_generation_from_blockchain.h b/tests/functional_tests/transactions_generation_from_blockchain.h
index cb5f94f80..70a2486d6 100644
--- a/tests/functional_tests/transactions_generation_from_blockchain.h
+++ b/tests/functional_tests/transactions_generation_from_blockchain.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/functional_tests/transfer.py b/tests/functional_tests/transfer.py
index f7a39fa0c..132758f50 100755
--- a/tests/functional_tests/transfer.py
+++ b/tests/functional_tests/transfer.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
@@ -55,7 +55,7 @@ class TransferTest():
def reset(self):
print('Resetting blockchain')
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
res = daemon.get_height()
daemon.pop_blocks(res.height - 1)
daemon.flush_txpool()
@@ -69,7 +69,7 @@ class TransferTest():
]
self.wallet = [None] * len(seeds)
for i in range(len(seeds)):
- self.wallet[i] = Wallet(idx = i + 4)
+ self.wallet[i] = Wallet(idx = i)
# close the wallet if any, will throw if none is loaded
try: self.wallet[i].close_wallet()
except: pass
@@ -77,7 +77,7 @@ class TransferTest():
def mine(self):
print("Mining some blocks")
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
res = daemon.get_info()
height = res.height
@@ -89,7 +89,7 @@ class TransferTest():
assert res.height == height + 80
def transfer(self):
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
print("Creating transfer to self")
@@ -508,7 +508,7 @@ class TransferTest():
def check_get_bulk_payments(self):
print('Checking get_bulk_payments')
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
res = daemon.get_info()
height = res.height
@@ -544,7 +544,7 @@ class TransferTest():
def check_get_payments(self):
print('Checking get_payments')
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
res = daemon.get_info()
height = res.height
@@ -587,8 +587,7 @@ class TransferTest():
assert len(res.tx_blob_list) == 1
txes[i][1] = res.tx_blob_list[0]
- daemon = Daemon(idx = 2)
- restricted_daemon = Daemon(idx = 2, restricted_rpc = True)
+ daemon = Daemon()
res = daemon.send_raw_transaction(txes[0][1])
assert res.not_relayed == False
assert res.low_mixin == False
@@ -599,18 +598,6 @@ class TransferTest():
assert res.overspend == False
assert res.fee_too_low == False
- res = restricted_daemon.send_raw_transaction(txes[0][1])
- assert res.not_relayed == False
- assert res.low_mixin == False
- assert res.double_spend == False
- assert res.invalid_input == False
- assert res.invalid_output == False
- assert res.too_big == False
- assert res.overspend == False
- assert res.fee_too_low == False
-
- res = restricted_daemon.get_transactions([txes[0][0]])
- assert not 'txs' in res or len(res.txs) == 0
res = daemon.get_transactions([txes[0][0]])
assert len(res.txs) >= 1
tx = [tx for tx in res.txs if tx.tx_hash == txes[0][0]][0]
@@ -628,19 +615,6 @@ class TransferTest():
assert res.fee_too_low == False
assert res.too_few_outputs == False
- res = restricted_daemon.send_raw_transaction(txes[1][1])
- assert res.not_relayed == False
- assert res.low_mixin == False
- assert res.double_spend == True
- assert res.invalid_input == False
- assert res.invalid_output == False
- assert res.too_big == False
- assert res.overspend == False
- assert res.fee_too_low == False
- assert res.too_few_outputs == False
-
- res = restricted_daemon.get_transactions([txes[0][0]])
- assert not 'txs' in res or len(res.txs) == 0
res = daemon.get_transactions([txes[0][0]])
assert len(res.txs) >= 1
tx = [tx for tx in res.txs if tx.tx_hash == txes[0][0]][0]
@@ -649,13 +623,13 @@ class TransferTest():
def sweep_dust(self):
print("Sweeping dust")
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
self.wallet[0].refresh()
res = self.wallet[0].sweep_dust()
assert not 'tx_hash_list' in res or len(res.tx_hash_list) == 0 # there's just one, but it cannot meet the fee
def sweep_single(self):
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
print("Sending single output")
@@ -711,7 +685,7 @@ class TransferTest():
assert len([t for t in res.transfers if t.key_image == ki]) == 1
def check_destinations(self):
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
print("Checking transaction destinations")
@@ -767,7 +741,7 @@ class TransferTest():
self.wallet[0].refresh()
def check_tx_notes(self):
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
print('Testing tx notes')
res = self.wallet[0].get_transfers()
@@ -784,7 +758,7 @@ class TransferTest():
assert res.notes == ['out txid', 'in txid']
def check_rescan(self):
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
print('Testing rescan_spent')
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
@@ -824,7 +798,7 @@ class TransferTest():
assert sorted(old_t_out, key = lambda k: k['txid']) == sorted(new_t_out, key = lambda k: k['txid'])
def check_is_key_image_spent(self):
- daemon = Daemon(idx = 2)
+ daemon = Daemon()
print('Testing is_key_image_spent')
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
diff --git a/tests/functional_tests/txpool.py b/tests/functional_tests/txpool.py
index 2d7f69f3c..e886200da 100755
--- a/tests/functional_tests/txpool.py
+++ b/tests/functional_tests/txpool.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
@@ -45,14 +45,14 @@ class TransferTest():
def reset(self):
print('Resetting blockchain')
- daemon = Daemon(idx=2)
+ daemon = Daemon()
res = daemon.get_height()
daemon.pop_blocks(res.height - 1)
daemon.flush_txpool()
def create(self):
print('Creating wallet')
- wallet = Wallet(idx = 4)
+ wallet = Wallet()
# close the wallet if any, will throw if none is loaded
try: wallet.close_wallet()
except: pass
@@ -61,8 +61,8 @@ class TransferTest():
def mine(self):
print("Mining some blocks")
- daemon = Daemon(idx = 2)
- wallet = Wallet(idx = 4)
+ daemon = Daemon()
+ wallet = Wallet()
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 80)
wallet.refresh()
@@ -70,8 +70,8 @@ class TransferTest():
def create_txes(self, address, ntxes):
print('Creating ' + str(ntxes) + ' transactions')
- daemon = Daemon(idx = 2)
- wallet = Wallet(idx = 4)
+ daemon = Daemon()
+ wallet = Wallet()
dst = {'address': address, 'amount': 1000000000000}
@@ -83,10 +83,8 @@ class TransferTest():
return txes
def check_empty_pool(self):
- self.check_empty_rpc_pool(Daemon(idx = 2))
- self.check_empty_rpc_pool(Daemon(idx = 2, restricted_rpc = True))
+ daemon = Daemon()
- def check_empty_rpc_pool(self, daemon):
res = daemon.get_transaction_pool_hashes()
assert not 'tx_hashes' in res or len(res.tx_hashes) == 0
res = daemon.get_transaction_pool_stats()
@@ -105,9 +103,8 @@ class TransferTest():
assert res.pool_stats.num_double_spends == 0
def check_txpool(self):
- daemon = Daemon(idx = 2)
- restricted_daemon = Daemon(idx = 2, restricted_rpc = True)
- wallet = Wallet(idx = 4)
+ daemon = Daemon()
+ wallet = Wallet()
res = daemon.get_info()
height = res.height
@@ -120,7 +117,6 @@ class TransferTest():
res = daemon.get_info()
assert res.tx_pool_size == txpool_size + 5
txpool_size = res.tx_pool_size
- self.check_empty_rpc_pool(restricted_daemon)
res = daemon.get_transaction_pool()
assert len(res.transactions) == txpool_size
@@ -164,7 +160,6 @@ class TransferTest():
print('Flushing 2 transactions')
txes_keys = list(txes.keys())
daemon.flush_txpool([txes_keys[1], txes_keys[3]])
- self.check_empty_rpc_pool(restricted_daemon)
res = daemon.get_transaction_pool()
assert len(res.transactions) == txpool_size - 2
assert len([x for x in res.transactions if x.id_hash == txes_keys[1]]) == 0
@@ -215,7 +210,6 @@ class TransferTest():
print('Flushing unknown transactions')
unknown_txids = ['1'*64, '2'*64, '3'*64]
daemon.flush_txpool(unknown_txids)
- self.check_empty_rpc_pool(restricted_daemon)
res = daemon.get_transaction_pool()
assert len(res.transactions) == txpool_size - 2
@@ -247,6 +241,17 @@ class TransferTest():
assert x.fee == txes[txid].fee
assert x.tx_blob == txes[txid].tx_blob
+ print('Checking relaying txes')
+ res = daemon.get_transaction_pool_hashes()
+ assert len(res.tx_hashes) > 0
+ txid = res.tx_hashes[0]
+ daemon.relay_tx([txid])
+ res = daemon.get_transactions([txid])
+ assert len(res.txs) == 1
+ assert res.txs[0].tx_hash == txid
+ assert res.txs[0].in_pool
+ assert res.txs[0].relayed
+
daemon.flush_txpool()
self.check_empty_pool()
diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py
index f759b316a..c193ac926 100755
--- a/tests/functional_tests/uri.py
+++ b/tests/functional_tests/uri.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
#encoding=utf-8
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/functional_tests/validate_address.py b/tests/functional_tests/validate_address.py
index 7c3d8abfa..d201cdf68 100755
--- a/tests/functional_tests/validate_address.py
+++ b/tests/functional_tests/validate_address.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
@@ -94,7 +94,7 @@ class AddressValidationTest():
def check_openalias_addresses(self):
print('Validating openalias addresses')
addresses = [
- ['donate@getmonero.org', '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A']
+ ['donate@getmonero.org', '888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H']
]
for address in addresses:
res = self.wallet.validate_address(address[0])
@@ -102,7 +102,7 @@ class AddressValidationTest():
res = self.wallet.validate_address(address[0], allow_openalias = True)
assert res.valid
assert not res.integrated
- assert not res.subaddress
+ assert res.subaddress
assert res.nettype == 'mainnet'
assert res.openalias_address == address[1]
diff --git a/tests/functional_tests/wallet.py b/tests/functional_tests/wallet.py
index 5bb3ec80a..91164daf9 100755
--- a/tests/functional_tests/wallet.py
+++ b/tests/functional_tests/wallet.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
#encoding=utf-8
-# Copyright (c) 2019 The Monero Project
+# Copyright (c) 2019-2020 The Monero Project
#
# All rights reserved.
#
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
index a6ef139f5..48a49edab 100644
--- a/tests/fuzz/CMakeLists.txt
+++ b/tests/fuzz/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -34,7 +34,8 @@ target_link_libraries(block_fuzz_tests
epee
device
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET block_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -47,7 +48,8 @@ target_link_libraries(transaction_fuzz_tests
epee
device
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET transaction_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -61,7 +63,8 @@ target_link_libraries(signature_fuzz_tests
epee
device
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET signature_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -75,7 +78,8 @@ target_link_libraries(cold-outputs_fuzz_tests
epee
device
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET cold-outputs_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -89,7 +93,8 @@ target_link_libraries(cold-transaction_fuzz_tests
epee
device
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET cold-transaction_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -101,7 +106,8 @@ target_link_libraries(load-from-binary_fuzz_tests
epee
${Boost_PROGRAM_OPTIONS_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET load-from-binary_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -113,7 +119,8 @@ target_link_libraries(load-from-json_fuzz_tests
epee
${Boost_PROGRAM_OPTIONS_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET load-from-json_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -125,7 +132,8 @@ target_link_libraries(base58_fuzz_tests
epee
${Boost_PROGRAM_OPTIONS_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET base58_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -138,7 +146,8 @@ target_link_libraries(parse-url_fuzz_tests
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET parse-url_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -153,7 +162,8 @@ target_link_libraries(http-client_fuzz_tests
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET http-client_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -168,7 +178,8 @@ target_link_libraries(levin_fuzz_tests
${Boost_REGEX_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET levin_fuzz_tests
PROPERTY
FOLDER "tests")
@@ -183,8 +194,27 @@ target_link_libraries(bulletproof_fuzz_tests
${Boost_REGEX_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
set_property(TARGET bulletproof_fuzz_tests
PROPERTY
FOLDER "tests")
+add_executable(tx-extra_fuzz_tests tx-extra.cpp fuzzer.cpp)
+target_link_libraries(tx-extra_fuzz_tests
+ PRIVATE
+ cryptonote_basic
+ common
+ epee
+ ${Boost_THREAD_LIBRARY}
+ ${Boost_CHRONO_LIBRARY}
+ ${Boost_REGEX_LIBRARY}
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_SYSTEM_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${EXTRA_LIBRARIES}
+ $ENV{LIB_FUZZING_ENGINE})
+set_property(TARGET tx-extra_fuzz_tests
+ PROPERTY
+ FOLDER "tests")
+
diff --git a/tests/fuzz/base58.cpp b/tests/fuzz/base58.cpp
index 5f909a5d9..3a06353ec 100644
--- a/tests/fuzz/base58.cpp
+++ b/tests/fuzz/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -27,50 +27,13 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "include_base_utils.h"
-#include "file_io_utils.h"
#include "common/base58.h"
#include "fuzzer.h"
-class Base58Fuzzer: public Fuzzer
-{
-public:
- Base58Fuzzer() {}
- virtual int init();
- virtual int run(const std::string &filename);
-};
-
-int Base58Fuzzer::init()
-{
- return 0;
-}
-
-int Base58Fuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- try
- {
- std::string data;
- tools::base58::decode(s, data);
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to load from binary: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- Base58Fuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
+BEGIN_SIMPLE_FUZZER()
+ std::string data;
+ tools::base58::decode(std::string((const char*)buf, len), data);
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/block.cpp b/tests/fuzz/block.cpp
index 850c58890..f8be29842 100644
--- a/tests/fuzz/block.cpp
+++ b/tests/fuzz/block.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,36 +33,10 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "fuzzer.h"
-class BlockFuzzer: public Fuzzer
-{
-public:
- virtual int run(const std::string &filename);
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
-private:
-};
-
-int BlockFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
+BEGIN_SIMPLE_FUZZER()
cryptonote::block b = AUTO_VAL_INIT(b);
- if(!parse_and_validate_block_from_blob(s, b))
- {
- std::cout << "Error: failed to parse block from file " << filename << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- BlockFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+ parse_and_validate_block_from_blob(std::string((const char*)buf, len), b);
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/bulletproof.cpp b/tests/fuzz/bulletproof.cpp
index e9a6ded7d..e0f183bc5 100644
--- a/tests/fuzz/bulletproof.cpp
+++ b/tests/fuzz/bulletproof.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,40 +33,13 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "fuzzer.h"
-class BulletproofFuzzer: public Fuzzer
-{
-public:
- virtual int run(const std::string &filename);
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
-private:
-};
-
-int BulletproofFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
+BEGIN_SIMPLE_FUZZER()
std::stringstream ss;
- ss << s;
+ ss << std::string((const char*)buf, len);
binary_archive<false> ba(ss);
rct::Bulletproof proof = AUTO_VAL_INIT(proof);
- bool r = ::serialization::serialize(ba, proof);
- if(!r)
- {
- std::cout << "Error: failed to parse bulletproof from file " << filename << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- BulletproofFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+ ::serialization::serialize(ba, proof);
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/cold-outputs.cpp b/tests/fuzz/cold-outputs.cpp
index f4050c948..fea235079 100644
--- a/tests/fuzz/cold-outputs.cpp
+++ b/tests/fuzz/cold-outputs.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,70 +34,28 @@
#include "wallet/wallet2.h"
#include "fuzzer.h"
-class ColdOutputsFuzzer: public Fuzzer
-{
-public:
- ColdOutputsFuzzer(): wallet(cryptonote::TESTNET) {}
- virtual int init();
- virtual int run(const std::string &filename);
+static tools::wallet2 *wallet = NULL;
-private:
- tools::wallet2 wallet;
-};
+BEGIN_INIT_SIMPLE_FUZZER()
+ static tools::wallet2 local_wallet;
+ wallet = &local_wallet;
-int ColdOutputsFuzzer::init()
-{
static const char * const spendkey_hex = "0b4f47697ec99c3de6579304e5f25c68b07afbe55b71d99620bf6cbf4e45a80f";
crypto::secret_key spendkey;
epee::string_tools::hex_to_pod(spendkey_hex, spendkey);
- try
- {
- wallet.init("", boost::none, boost::asio::ip::tcp::endpoint{}, 0, true, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
- wallet.set_subaddress_lookahead(1, 1);
- wallet.generate("", "", spendkey, true, false);
- }
- catch (const std::exception &e)
- {
- std::cerr << "Error on ColdOutputsFuzzer::init: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int ColdOutputsFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- s = std::string("\x01\x16serialization::archive") + s;
- try
- {
- std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
- std::stringstream iss;
- iss << s;
- boost::archive::portable_binary_iarchive ar(iss);
- ar >> outputs;
- size_t n_outputs = wallet.import_outputs(outputs);
- std::cout << boost::lexical_cast<std::string>(n_outputs) << " outputs imported" << std::endl;
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to import outputs: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- ColdOutputsFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
-
+ wallet->init("", boost::none, boost::asio::ip::tcp::endpoint{}, 0, true, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
+ wallet->set_subaddress_lookahead(1, 1);
+ wallet->generate("", "", spendkey, true, false);
+END_INIT_SIMPLE_FUZZER()
+
+BEGIN_SIMPLE_FUZZER()
+ std::string s = std::string("\x01\x16serialization::archive") + std::string((const char*)buf, len);
+ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
+ std::stringstream iss;
+ iss << s;
+ boost::archive::portable_binary_iarchive ar(iss);
+ ar >> outputs;
+ size_t n_outputs = wallet->import_outputs(outputs);
+ std::cout << boost::lexical_cast<std::string>(n_outputs) << " outputs imported" << std::endl;
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/cold-transaction.cpp b/tests/fuzz/cold-transaction.cpp
index 08117281b..32c84ac74 100644
--- a/tests/fuzz/cold-transaction.cpp
+++ b/tests/fuzz/cold-transaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,71 +34,29 @@
#include "wallet/wallet2.h"
#include "fuzzer.h"
-class ColdTransactionFuzzer: public Fuzzer
-{
-public:
- ColdTransactionFuzzer(): wallet(cryptonote::TESTNET) {}
- virtual int init();
- virtual int run(const std::string &filename);
+static tools::wallet2 *wallet = NULL;
-private:
- tools::wallet2 wallet;
-};
+BEGIN_INIT_SIMPLE_FUZZER()
+ static tools::wallet2 local_wallet;
+ wallet = &local_wallet;
-
-int ColdTransactionFuzzer::init()
-{
static const char * const spendkey_hex = "0b4f47697ec99c3de6579304e5f25c68b07afbe55b71d99620bf6cbf4e45a80f";
crypto::secret_key spendkey;
epee::string_tools::hex_to_pod(spendkey_hex, spendkey);
- try
- {
- wallet.init("", boost::none, boost::asio::ip::tcp::endpoint{}, 0, true, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
- wallet.set_subaddress_lookahead(1, 1);
- wallet.generate("", "", spendkey, true, false);
- }
- catch (const std::exception &e)
- {
- std::cerr << "Error on ColdTransactionFuzzer::init: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int ColdTransactionFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- s = std::string("\x01\x16serialization::archive") + s;
- try
- {
- tools::wallet2::unsigned_tx_set exported_txs;
- std::stringstream iss;
- iss << s;
- boost::archive::portable_binary_iarchive ar(iss);
- ar >> exported_txs;
- std::vector<tools::wallet2::pending_tx> ptx;
- bool success = wallet.sign_tx(exported_txs, "/tmp/cold-transaction-test-signed", ptx);
- std::cout << (success ? "signed" : "error") << std::endl;
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to sign transaction: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- ColdTransactionFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+ wallet->init("", boost::none, boost::asio::ip::tcp::endpoint{}, 0, true, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
+ wallet->set_subaddress_lookahead(1, 1);
+ wallet->generate("", "", spendkey, true, false);
+END_INIT_SIMPLE_FUZZER()
+
+BEGIN_SIMPLE_FUZZER()
+ std::string s = std::string("\x01\x16serialization::archive") + std::string((const char*)buf, len);
+ tools::wallet2::unsigned_tx_set exported_txs;
+ std::stringstream iss;
+ iss << s;
+ boost::archive::portable_binary_iarchive ar(iss);
+ ar >> exported_txs;
+ std::vector<tools::wallet2::pending_tx> ptx;
+ bool success = wallet->sign_tx(exported_txs, "/tmp/cold-transaction-test-signed", ptx);
+ std::cout << (success ? "signed" : "error") << std::endl;
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/fuzzer.cpp b/tests/fuzz/fuzzer.cpp
index 24db5ee05..eaaef5aa5 100644
--- a/tests/fuzz/fuzzer.cpp
+++ b/tests/fuzz/fuzzer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,6 +33,8 @@
#include "common/util.h"
#include "fuzzer.h"
+#ifndef OSSFUZZ
+
#if (!defined(__clang__) || (__clang__ < 5))
static int __AFL_LOOP(int)
{
@@ -74,3 +76,5 @@ int run_fuzzer(int argc, const char **argv, Fuzzer &fuzzer)
CATCH_ENTRY_L0("run_fuzzer", 1);
}
+
+#endif
diff --git a/tests/fuzz/fuzzer.h b/tests/fuzz/fuzzer.h
index 5cbd1abc2..f45e69f73 100644
--- a/tests/fuzz/fuzzer.h
+++ b/tests/fuzz/fuzzer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -27,6 +27,56 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
+#include "file_io_utils.h"
+
+#ifdef OSSFUZZ
+
+#define BEGIN_INIT_SIMPLE_FUZZER() \
+ static int init() \
+ { \
+ try \
+ {
+
+#define END_INIT_SIMPLE_FUZZER() \
+ } \
+ catch (const std::exception &e) \
+ { \
+ fprintf(stderr, "Exception: %s\n", e.what()); \
+ return 1; \
+ } \
+ return 0; \
+ }
+
+#define BEGIN_SIMPLE_FUZZER() \
+extern "C" { \
+ int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) \
+ { \
+ try \
+ { \
+ static bool first = true; \
+ if (first) \
+ { \
+ if (init()) \
+ return 1; \
+ first = false; \
+ } \
+
+#define END_SIMPLE_FUZZER() \
+ } \
+ catch (const std::exception &e) \
+ { \
+ fprintf(stderr, "Exception: %s\n", e.what()); \
+ delete el::base::elStorage; \
+ el::base::elStorage = NULL; \
+ return 0; \
+ } \
+ delete el::base::elStorage; \
+ el::base::elStorage = NULL; \
+ return 0; \
+ } \
+}
+
+#else
class Fuzzer
{
@@ -36,3 +86,61 @@ public:
};
int run_fuzzer(int argc, const char **argv, Fuzzer &fuzzer);
+
+#define BEGIN_INIT_SIMPLE_FUZZER() \
+ class SimpleFuzzer: public Fuzzer \
+ { \
+ virtual int init() \
+ { \
+ try \
+ {
+
+#define END_INIT_SIMPLE_FUZZER() \
+ } \
+ catch (const std::exception &e) \
+ { \
+ fprintf(stderr, "Exception: %s\n", e.what()); \
+ return 1; \
+ } \
+ return 0; \
+ }
+
+#define BEGIN_SIMPLE_FUZZER() \
+ virtual int run(const std::string &filename) \
+ { \
+ try \
+ { \
+ std::string s; \
+ if (!epee::file_io_utils::load_file_to_string(filename, s)) \
+ { \
+ std::cout << "Error: failed to load file " << filename << std::endl; \
+ return 1; \
+ } \
+ const uint8_t *buf = (const uint8_t*)s.data(); \
+ const size_t len = s.size(); \
+ {
+
+#define END_SIMPLE_FUZZER() \
+ } \
+ } \
+ catch (const std::exception &e) \
+ { \
+ fprintf(stderr, "Exception: %s\n", e.what()); \
+ delete el::base::elStorage; \
+ el::base::elStorage = NULL; \
+ return 0; \
+ } \
+ delete el::base::elStorage; \
+ el::base::elStorage = NULL; \
+ return 0; \
+ } \
+ }; \
+ int main(int argc, const char **argv) \
+ { \
+ TRY_ENTRY(); \
+ SimpleFuzzer fuzzer; \
+ return run_fuzzer(argc, argv, fuzzer); \
+ CATCH_ENTRY_L0("main", 1); \
+ }
+
+#endif
diff --git a/tests/fuzz/http-client.cpp b/tests/fuzz/http-client.cpp
index ea6d5a2ad..4b12b36bb 100644
--- a/tests/fuzz/http-client.cpp
+++ b/tests/fuzz/http-client.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -58,48 +58,11 @@ private:
std::string data;
};
-class HTTPClientFuzzer: public Fuzzer
-{
-public:
- HTTPClientFuzzer() {}
- virtual int init();
- virtual int run(const std::string &filename);
-
-private:
- epee::net_utils::http::http_simple_client_template<dummy_client> client;
-};
-
-int HTTPClientFuzzer::init()
-{
- return 0;
-}
-
-int HTTPClientFuzzer::run(const std::string &filename)
-{
- std::string s;
+static epee::net_utils::http::http_simple_client_template<dummy_client> client;
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- try
- {
- client.test(s, std::chrono::milliseconds(1000));
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to test http client: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- HTTPClientFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
+BEGIN_SIMPLE_FUZZER()
+ client.test(std::string((const char*)buf, len), std::chrono::milliseconds(1000));
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/levin.cpp b/tests/fuzz/levin.cpp
index 6c16a0a85..012d05f36 100644
--- a/tests/fuzz/levin.cpp
+++ b/tests/fuzz/levin.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -279,26 +279,10 @@ namespace
#endif
}
-class LevinFuzzer: public Fuzzer
-{
-public:
- LevinFuzzer() {} //: handler(endpoint, config, context) {}
- virtual int init();
- virtual int run(const std::string &filename);
-
-private:
- //epee::net_utils::connection_context_base context;
- //epee::levin::async_protocol_handler<> handler;
-};
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
-int LevinFuzzer::init()
-{
- return 0;
-}
-
-int LevinFuzzer::run(const std::string &filename)
-{
- std::string s;
+BEGIN_SIMPLE_FUZZER()
#if 0
epee::levin::bucket_head2 req_head;
@@ -313,13 +297,6 @@ int LevinFuzzer::run(const std::string &filename)
fwrite(&req_head,sizeof(req_head),1, f);
fclose(f);
#endif
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- try
- {
//std::unique_ptr<test_connection> conn = new test();
boost::asio::io_service io_service;
test_levin_protocol_handler_config m_handler_config;
@@ -329,21 +306,5 @@ int LevinFuzzer::run(const std::string &filename)
conn->start();
//m_commands_handler.invoke_out_buf(expected_out_data);
//m_commands_handler.return_code(expected_return_code);
- conn->m_protocol_handler.handle_recv(s.data(), s.size());
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to test http client: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- LevinFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
-
+ conn->m_protocol_handler.handle_recv(buf, len);
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/load_from_binary.cpp b/tests/fuzz/load_from_binary.cpp
index 85b7361e5..6d6826e2e 100644
--- a/tests/fuzz/load_from_binary.cpp
+++ b/tests/fuzz/load_from_binary.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,46 +33,10 @@
#include "storages/portable_storage_base.h"
#include "fuzzer.h"
-class PortableStorageFuzzer: public Fuzzer
-{
-public:
- PortableStorageFuzzer() {}
- virtual int init();
- virtual int run(const std::string &filename);
-};
-
-int PortableStorageFuzzer::init()
-{
- return 0;
-}
-
-int PortableStorageFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- try
- {
- epee::serialization::portable_storage ps;
- ps.load_from_binary(s);
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to load from binary: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- PortableStorageFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
+BEGIN_SIMPLE_FUZZER()
+ epee::serialization::portable_storage ps;
+ ps.load_from_binary(std::string((const char*)buf, len));
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/load_from_json.cpp b/tests/fuzz/load_from_json.cpp
index 3ba98050b..8788a92b6 100644
--- a/tests/fuzz/load_from_json.cpp
+++ b/tests/fuzz/load_from_json.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,46 +33,10 @@
#include "storages/portable_storage_base.h"
#include "fuzzer.h"
-class PortableStorageFuzzer: public Fuzzer
-{
-public:
- PortableStorageFuzzer() {}
- virtual int init();
- virtual int run(const std::string &filename);
-};
-
-int PortableStorageFuzzer::init()
-{
- return 0;
-}
-
-int PortableStorageFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- try
- {
- epee::serialization::portable_storage ps;
- ps.load_from_json(s);
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to load from binary: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- PortableStorageFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
+BEGIN_SIMPLE_FUZZER()
+ epee::serialization::portable_storage ps;
+ ps.load_from_json(std::string((const char*)buf, len));
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/parse_url.cpp b/tests/fuzz/parse_url.cpp
index 3db78f9d9..cc1323eb5 100644
--- a/tests/fuzz/parse_url.cpp
+++ b/tests/fuzz/parse_url.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -31,46 +31,10 @@
#include "net/net_parse_helpers.h"
#include "fuzzer.h"
-class ParseURLFuzzer: public Fuzzer
-{
-public:
- ParseURLFuzzer() {}
- virtual int init();
- virtual int run(const std::string &filename);
-};
-
-int ParseURLFuzzer::init()
-{
- return 0;
-}
-
-int ParseURLFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
- try
- {
- epee::net_utils::http::url_content url;
- epee::net_utils::parse_url(s, url);
- }
- catch (const std::exception &e)
- {
- std::cerr << "Failed to load from binary: " << e.what() << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- ParseURLFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
+BEGIN_SIMPLE_FUZZER()
+ epee::net_utils::http::url_content url;
+ epee::net_utils::parse_url(std::string((const char*)buf, len), url);
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/signature.cpp b/tests/fuzz/signature.cpp
index 038378ae2..8f528b20e 100644
--- a/tests/fuzz/signature.cpp
+++ b/tests/fuzz/signature.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,66 +34,31 @@
#include "wallet/wallet2.h"
#include "fuzzer.h"
-class SignatureFuzzer: public Fuzzer
-{
-public:
- SignatureFuzzer(): Fuzzer(), wallet(cryptonote::TESTNET) {}
- virtual int init();
- virtual int run(const std::string &filename);
+static tools::wallet2 *wallet = NULL;
+static cryptonote::account_public_address address;
-private:
- tools::wallet2 wallet;
- cryptonote::account_public_address address;
-};
+BEGIN_INIT_SIMPLE_FUZZER()
+ static tools::wallet2 local_wallet(cryptonote::TESTNET);
+ wallet = &local_wallet;
-int SignatureFuzzer::init()
-{
static const char * const spendkey_hex = "0b4f47697ec99c3de6579304e5f25c68b07afbe55b71d99620bf6cbf4e45a80f";
crypto::secret_key spendkey;
epee::string_tools::hex_to_pod(spendkey_hex, spendkey);
- try
- {
- wallet.init("", boost::none, boost::asio::ip::tcp::endpoint{}, 0, true, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
- wallet.set_subaddress_lookahead(1, 1);
- wallet.generate("", "", spendkey, true, false);
+ wallet->init("", boost::none, boost::asio::ip::tcp::endpoint{}, 0, true, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
+ wallet->set_subaddress_lookahead(1, 1);
+ wallet->generate("", "", spendkey, true, false);
- cryptonote::address_parse_info info;
- if (!cryptonote::get_account_address_from_str_or_url(info, cryptonote::TESTNET, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN"))
- {
- std::cerr << "failed to parse address" << std::endl;
- return 1;
- }
- address = info.address;
- }
- catch (const std::exception &e)
+ cryptonote::address_parse_info info;
+ if (!cryptonote::get_account_address_from_str_or_url(info, cryptonote::TESTNET, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN"))
{
- std::cerr << "Error on SignatureFuzzer::init: " << e.what() << std::endl;
+ std::cerr << "failed to parse address" << std::endl;
return 1;
}
- return 0;
-}
-
-int SignatureFuzzer::run(const std::string &filename)
-{
- std::string s;
+ address = info.address;
+END_INIT_SIMPLE_FUZZER()
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
-
- bool valid = wallet.verify("test", address, s);
+BEGIN_SIMPLE_FUZZER()
+ bool valid = wallet->verify("test", address, std::string((const char*)buf, len));
std::cout << "Signature " << (valid ? "valid" : "invalid") << std::endl;
-
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- SignatureFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/transaction.cpp b/tests/fuzz/transaction.cpp
index 0f62888a1..94f0a849f 100644
--- a/tests/fuzz/transaction.cpp
+++ b/tests/fuzz/transaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
@@ -33,36 +33,10 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "fuzzer.h"
-class TransactionFuzzer: public Fuzzer
-{
-public:
- virtual int run(const std::string &filename);
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
-private:
-};
-
-int TransactionFuzzer::run(const std::string &filename)
-{
- std::string s;
-
- if (!epee::file_io_utils::load_file_to_string(filename, s))
- {
- std::cout << "Error: failed to load file " << filename << std::endl;
- return 1;
- }
+BEGIN_SIMPLE_FUZZER()
cryptonote::transaction tx = AUTO_VAL_INIT(tx);
- if(!parse_and_validate_tx_from_blob(s, tx))
- {
- std::cout << "Error: failed to parse transaction from file " << filename << std::endl;
- return 1;
- }
- return 0;
-}
-
-int main(int argc, const char **argv)
-{
- TRY_ENTRY();
- TransactionFuzzer fuzzer;
- return run_fuzzer(argc, argv, fuzzer);
- CATCH_ENTRY_L0("main", 1);
-}
+ parse_and_validate_tx_from_blob(std::string((const char*)buf, len), tx);
+END_SIMPLE_FUZZER()
diff --git a/tests/fuzz/tx-extra.cpp b/tests/fuzz/tx-extra.cpp
new file mode 100644
index 000000000..35b14b802
--- /dev/null
+++ b/tests/fuzz/tx-extra.cpp
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "include_base_utils.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "fuzzer.h"
+
+BEGIN_INIT_SIMPLE_FUZZER()
+END_INIT_SIMPLE_FUZZER()
+
+BEGIN_SIMPLE_FUZZER()
+ std::vector<cryptonote::tx_extra_field> tx_extra_fields;
+ cryptonote::parse_tx_extra(std::vector<uint8_t>(buf, buf + len), tx_extra_fields);
+END_SIMPLE_FUZZER()
+
diff --git a/tests/hash-target.cpp b/tests/hash-target.cpp
index e95475cac..038eaab47 100644
--- a/tests/hash-target.cpp
+++ b/tests/hash-target.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/hash/CMakeLists.txt b/tests/hash/CMakeLists.txt
index a0c78bfdc..91dfdff1e 100644
--- a/tests/hash/CMakeLists.txt
+++ b/tests/hash/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/hash/main.cpp b/tests/hash/main.cpp
index d62098a60..bf612684c 100644
--- a/tests/hash/main.cpp
+++ b/tests/hash/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/io.h b/tests/io.h
index 0f65ed297..f5e2b518d 100644
--- a/tests/io.h
+++ b/tests/io.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/libwallet_api_tests/CMakeLists.txt b/tests/libwallet_api_tests/CMakeLists.txt
index cb1d563b0..8d03399fa 100644
--- a/tests/libwallet_api_tests/CMakeLists.txt
+++ b/tests/libwallet_api_tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp
index c34da04b7..8413d8621 100644
--- a/tests/libwallet_api_tests/main.cpp
+++ b/tests/libwallet_api_tests/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/net_load_tests/CMakeLists.txt b/tests/net_load_tests/CMakeLists.txt
index 40b5561a7..9bcc2d6ab 100644
--- a/tests/net_load_tests/CMakeLists.txt
+++ b/tests/net_load_tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp
index e154363e7..b55f73971 100644
--- a/tests/net_load_tests/clt.cpp
+++ b/tests/net_load_tests/clt.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/net_load_tests/net_load_tests.h b/tests/net_load_tests/net_load_tests.h
index 4a76f2ec6..882d42c02 100644
--- a/tests/net_load_tests/net_load_tests.h
+++ b/tests/net_load_tests/net_load_tests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp
index b42b1e1b0..84d97ebd4 100644
--- a/tests/net_load_tests/srv.cpp
+++ b/tests/net_load_tests/srv.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/CMakeLists.txt b/tests/performance_tests/CMakeLists.txt
index b36df10dc..1a9da116f 100644
--- a/tests/performance_tests/CMakeLists.txt
+++ b/tests/performance_tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/tests/performance_tests/bulletproof.h b/tests/performance_tests/bulletproof.h
index 7136fbbfe..835d518f6 100644
--- a/tests/performance_tests/bulletproof.h
+++ b/tests/performance_tests/bulletproof.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/check_hash.h b/tests/performance_tests/check_hash.h
index 294654f37..09737defb 100644
--- a/tests/performance_tests/check_hash.h
+++ b/tests/performance_tests/check_hash.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/check_tx_signature.h b/tests/performance_tests/check_tx_signature.h
index 329714c56..5122336e7 100644
--- a/tests/performance_tests/check_tx_signature.h
+++ b/tests/performance_tests/check_tx_signature.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/cn_fast_hash.h b/tests/performance_tests/cn_fast_hash.h
index 63b2c5bee..f2177232f 100644
--- a/tests/performance_tests/cn_fast_hash.h
+++ b/tests/performance_tests/cn_fast_hash.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/cn_slow_hash.h b/tests/performance_tests/cn_slow_hash.h
index 4f410d62d..e124e00b0 100644
--- a/tests/performance_tests/cn_slow_hash.h
+++ b/tests/performance_tests/cn_slow_hash.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/construct_tx.h b/tests/performance_tests/construct_tx.h
index ebfe46edf..6bf7a82ef 100644
--- a/tests/performance_tests/construct_tx.h
+++ b/tests/performance_tests/construct_tx.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/crypto_ops.h b/tests/performance_tests/crypto_ops.h
index 2859873ef..ae00bb517 100644
--- a/tests/performance_tests/crypto_ops.h
+++ b/tests/performance_tests/crypto_ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/derive_public_key.h b/tests/performance_tests/derive_public_key.h
index ad0b3b55f..7980d2cd4 100644
--- a/tests/performance_tests/derive_public_key.h
+++ b/tests/performance_tests/derive_public_key.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/derive_secret_key.h b/tests/performance_tests/derive_secret_key.h
index ba01b57c0..f395d0ccf 100644
--- a/tests/performance_tests/derive_secret_key.h
+++ b/tests/performance_tests/derive_secret_key.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/equality.h b/tests/performance_tests/equality.h
index 5788ebec8..1748ce096 100644
--- a/tests/performance_tests/equality.h
+++ b/tests/performance_tests/equality.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -35,7 +35,7 @@
struct memcmp32
{
- static const size_t loop_count = 1000000000;
+ static const size_t loop_count = 10000000;
static int call(const unsigned char *k0, const unsigned char *k1){ return memcmp(k0, k1, 32); }
};
diff --git a/tests/performance_tests/ge_frombytes_vartime.h b/tests/performance_tests/ge_frombytes_vartime.h
index 1a0601c74..1f70ec345 100644
--- a/tests/performance_tests/ge_frombytes_vartime.h
+++ b/tests/performance_tests/ge_frombytes_vartime.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/ge_tobytes.h b/tests/performance_tests/ge_tobytes.h
index 66e6fce38..2bcbfc9d7 100644
--- a/tests/performance_tests/ge_tobytes.h
+++ b/tests/performance_tests/ge_tobytes.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/generate_key_derivation.h b/tests/performance_tests/generate_key_derivation.h
index 1f0066589..ee6b2e4c7 100644
--- a/tests/performance_tests/generate_key_derivation.h
+++ b/tests/performance_tests/generate_key_derivation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/generate_key_image.h b/tests/performance_tests/generate_key_image.h
index df39d7088..53afd020b 100644
--- a/tests/performance_tests/generate_key_image.h
+++ b/tests/performance_tests/generate_key_image.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/generate_key_image_helper.h b/tests/performance_tests/generate_key_image_helper.h
index d4d83c07d..38ffa3e50 100644
--- a/tests/performance_tests/generate_key_image_helper.h
+++ b/tests/performance_tests/generate_key_image_helper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/generate_keypair.h b/tests/performance_tests/generate_keypair.h
index cf28f7f58..66c83162d 100644
--- a/tests/performance_tests/generate_keypair.h
+++ b/tests/performance_tests/generate_keypair.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/is_out_to_acc.h b/tests/performance_tests/is_out_to_acc.h
index 8b4516843..023a7a13b 100644
--- a/tests/performance_tests/is_out_to_acc.h
+++ b/tests/performance_tests/is_out_to_acc.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp
index d3ba57270..ca0528e16 100644
--- a/tests/performance_tests/main.cpp
+++ b/tests/performance_tests/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/multi_tx_test_base.h b/tests/performance_tests/multi_tx_test_base.h
index bdbbee37d..39ab6b26f 100644
--- a/tests/performance_tests/multi_tx_test_base.h
+++ b/tests/performance_tests/multi_tx_test_base.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/performance_tests.h b/tests/performance_tests/performance_tests.h
index 606c5980f..ae7aabe08 100644
--- a/tests/performance_tests/performance_tests.h
+++ b/tests/performance_tests/performance_tests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -195,7 +195,7 @@ void run_test(const std::string &filter, Params &params, const char* test_name)
scale = 1000;
time_per_call = runner.time_per_call(1000);
#ifdef _WIN32
- unit = "\xb5s";
+ unit = "us";
#else
unit = "µs";
#endif
diff --git a/tests/performance_tests/performance_utils.h b/tests/performance_tests/performance_utils.h
index 8a45bea90..8617058f4 100644
--- a/tests/performance_tests/performance_utils.h
+++ b/tests/performance_tests/performance_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/range_proof.h b/tests/performance_tests/range_proof.h
index 548237814..e1eef7343 100644
--- a/tests/performance_tests/range_proof.h
+++ b/tests/performance_tests/range_proof.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/rct_mlsag.h b/tests/performance_tests/rct_mlsag.h
index da0c064fd..638dd6385 100644
--- a/tests/performance_tests/rct_mlsag.h
+++ b/tests/performance_tests/rct_mlsag.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/sc_reduce32.h b/tests/performance_tests/sc_reduce32.h
index 8db1ca70a..8da9f8b3d 100644
--- a/tests/performance_tests/sc_reduce32.h
+++ b/tests/performance_tests/sc_reduce32.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/signature.h b/tests/performance_tests/signature.h
index 63c63ea46..44d4ad78c 100644
--- a/tests/performance_tests/signature.h
+++ b/tests/performance_tests/signature.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/single_tx_test_base.h b/tests/performance_tests/single_tx_test_base.h
index 52fbf5f80..59222be70 100644
--- a/tests/performance_tests/single_tx_test_base.h
+++ b/tests/performance_tests/single_tx_test_base.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/performance_tests/subaddress_expand.h b/tests/performance_tests/subaddress_expand.h
index 61fcb41f3..5bbf344a4 100644
--- a/tests/performance_tests/subaddress_expand.h
+++ b/tests/performance_tests/subaddress_expand.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt
index 9c24a5ec7..a5984b2c9 100644
--- a/tests/unit_tests/CMakeLists.txt
+++ b/tests/unit_tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
@@ -83,6 +83,7 @@ set(unit_tests_sources
test_peerlist.cpp
test_protocol_pack.cpp
threadpool.cpp
+ tx_proof.cpp
hardfork.cpp
unbound.cpp
uri.cpp
@@ -109,6 +110,7 @@ target_link_libraries(unit_tests
cryptonote_protocol
cryptonote_core
daemon_messages
+ daemon_rpc_server
blockchain_db
lmdb_lib
rpc
diff --git a/tests/unit_tests/account.cpp b/tests/unit_tests/account.cpp
index 7073ab3e8..68bf4dce7 100644
--- a/tests/unit_tests/account.cpp
+++ b/tests/unit_tests/account.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -29,14 +29,30 @@
#include "gtest/gtest.h"
#include "cryptonote_basic/account.h"
+#include "ringct/rctOps.h"
+// Tests in-memory encryption of account secret keys
TEST(account, encrypt_keys)
{
+ // Generate account keys and random multisig keys
cryptonote::keypair recovery_key = cryptonote::keypair::generate(hw::get_device("default"));
cryptonote::account_base account;
crypto::secret_key key = account.generate(recovery_key.sec);
+
+ const size_t n_multisig = 4;
+ std::vector<crypto::secret_key> multisig_keys;
+ multisig_keys.reserve(n_multisig);
+ multisig_keys.resize(0);
+ for (size_t i = 0; i < n_multisig; ++i)
+ {
+ multisig_keys.push_back(rct::rct2sk(rct::skGen()));
+ }
+ ASSERT_TRUE(account.make_multisig(account.get_keys().m_view_secret_key, account.get_keys().m_spend_secret_key, account.get_keys().m_account_address.m_spend_public_key, multisig_keys));
+
const cryptonote::account_keys keys = account.get_keys();
+ ASSERT_EQ(keys.m_multisig_keys.size(),n_multisig);
+ // Encrypt and decrypt keys
ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
ASSERT_EQ(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
ASSERT_EQ(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
@@ -50,22 +66,40 @@ TEST(account, encrypt_keys)
ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
ASSERT_NE(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+ ASSERT_NE(account.get_keys().m_multisig_keys, keys.m_multisig_keys);
account.decrypt_viewkey(chacha_key);
ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
ASSERT_EQ(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+ ASSERT_NE(account.get_keys().m_multisig_keys, keys.m_multisig_keys);
account.encrypt_viewkey(chacha_key);
ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
ASSERT_NE(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+ ASSERT_NE(account.get_keys().m_multisig_keys, keys.m_multisig_keys);
+
+ account.decrypt_viewkey(chacha_key);
+
+ ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
+ ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
+ ASSERT_EQ(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+ ASSERT_NE(account.get_keys().m_multisig_keys, keys.m_multisig_keys);
+
+ account.encrypt_viewkey(chacha_key);
+
+ ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
+ ASSERT_NE(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
+ ASSERT_NE(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+ ASSERT_NE(account.get_keys().m_multisig_keys, keys.m_multisig_keys);
account.decrypt_keys(chacha_key);
ASSERT_EQ(account.get_keys().m_account_address, keys.m_account_address);
ASSERT_EQ(account.get_keys().m_spend_secret_key, keys.m_spend_secret_key);
ASSERT_EQ(account.get_keys().m_view_secret_key, keys.m_view_secret_key);
+ ASSERT_EQ(account.get_keys().m_multisig_keys, keys.m_multisig_keys);
}
diff --git a/tests/unit_tests/address_from_url.cpp b/tests/unit_tests/address_from_url.cpp
index 4b06c6487..b6b205aac 100644
--- a/tests/unit_tests/address_from_url.cpp
+++ b/tests/unit_tests/address_from_url.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/apply_permutation.cpp b/tests/unit_tests/apply_permutation.cpp
index 76d10c8ff..9376dc10a 100644
--- a/tests/unit_tests/apply_permutation.cpp
+++ b/tests/unit_tests/apply_permutation.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/base58.cpp b/tests/unit_tests/base58.cpp
index 1996afd04..b7e9dfcf1 100644
--- a/tests/unit_tests/base58.cpp
+++ b/tests/unit_tests/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/block_queue.cpp b/tests/unit_tests/block_queue.cpp
index 0cba7c443..77c7f97ff 100644
--- a/tests/unit_tests/block_queue.cpp
+++ b/tests/unit_tests/block_queue.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/block_reward.cpp b/tests/unit_tests/block_reward.cpp
index 1dd9072b9..5f3335981 100644
--- a/tests/unit_tests/block_reward.cpp
+++ b/tests/unit_tests/block_reward.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/blockchain_db.cpp b/tests/unit_tests/blockchain_db.cpp
index 6b569d113..29cdd73b9 100644
--- a/tests/unit_tests/blockchain_db.cpp
+++ b/tests/unit_tests/blockchain_db.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/bulletproofs.cpp b/tests/unit_tests/bulletproofs.cpp
index a73b80848..7c6e459f5 100644
--- a/tests/unit_tests/bulletproofs.cpp
+++ b/tests/unit_tests/bulletproofs.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/canonical_amounts.cpp b/tests/unit_tests/canonical_amounts.cpp
index 74fcc9548..5c141098b 100644
--- a/tests/unit_tests/canonical_amounts.cpp
+++ b/tests/unit_tests/canonical_amounts.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/chacha.cpp b/tests/unit_tests/chacha.cpp
index e06081f8f..4e434de4d 100644
--- a/tests/unit_tests/chacha.cpp
+++ b/tests/unit_tests/chacha.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/checkpoints.cpp b/tests/unit_tests/checkpoints.cpp
index 90229a0b8..26f2b51f7 100644
--- a/tests/unit_tests/checkpoints.cpp
+++ b/tests/unit_tests/checkpoints.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/command_line.cpp b/tests/unit_tests/command_line.cpp
index 6d5afb708..09c41a33c 100644
--- a/tests/unit_tests/command_line.cpp
+++ b/tests/unit_tests/command_line.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp
index 7100c8013..7ac87ca7c 100644
--- a/tests/unit_tests/crypto.cpp
+++ b/tests/unit_tests/crypto.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/decompose_amount_into_digits.cpp b/tests/unit_tests/decompose_amount_into_digits.cpp
index 5049dd83d..a4c850bbe 100644
--- a/tests/unit_tests/decompose_amount_into_digits.cpp
+++ b/tests/unit_tests/decompose_amount_into_digits.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/difficulty.cpp b/tests/unit_tests/difficulty.cpp
index e9e3272f0..008b9a94f 100644
--- a/tests/unit_tests/difficulty.cpp
+++ b/tests/unit_tests/difficulty.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/dns_resolver.cpp b/tests/unit_tests/dns_resolver.cpp
index 6bffc01d8..b0157bb0a 100644
--- a/tests/unit_tests/dns_resolver.cpp
+++ b/tests/unit_tests/dns_resolver.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp
index 32989f545..71098f612 100644
--- a/tests/unit_tests/epee_boosted_tcp_server.cpp
+++ b/tests/unit_tests/epee_boosted_tcp_server.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/epee_levin_protocol_handler_async.cpp b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
index b27699a77..314fcf9f2 100644
--- a/tests/unit_tests/epee_levin_protocol_handler_async.cpp
+++ b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index 4f42140b3..0f91671a7 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -45,6 +45,7 @@
#include "boost/archive/portable_binary_iarchive.hpp"
#include "boost/archive/portable_binary_oarchive.hpp"
#include "byte_slice.h"
+#include "byte_stream.h"
#include "crypto/crypto.h"
#include "hex.h"
#include "net/net_utils_base.h"
@@ -386,6 +387,29 @@ TEST(ByteSlice, Construction)
EXPECT_FALSE(std::is_copy_assignable<epee::byte_slice>());
}
+TEST(ByteSlice, DataReturnedMatches)
+{
+ for (int i = 64; i > 0; i--)
+ {
+ std::string sso_string(i, 'a');
+ std::string original = sso_string;
+ epee::byte_slice slice{std::move(sso_string)};
+
+ EXPECT_EQ(slice.size(), original.size());
+ EXPECT_EQ(memcmp(slice.data(), original.data(), original.size()), 0);
+ }
+
+ for (int i = 64; i > 0; i--)
+ {
+ std::vector<uint8_t> sso_vector(i, 'a');
+ std::vector<uint8_t> original = sso_vector;
+ epee::byte_slice slice{std::move(sso_vector)};
+
+ EXPECT_EQ(slice.size(), original.size());
+ EXPECT_EQ(memcmp(slice.data(), original.data(), original.size()), 0);
+ }
+}
+
TEST(ByteSlice, NoExcept)
{
EXPECT_TRUE(std::is_nothrow_default_constructible<epee::byte_slice>());
@@ -666,6 +690,23 @@ TEST(ByteSlice, TakeSlice)
EXPECT_TRUE(boost::range::equal(base_string, slice));
const epee::span<const std::uint8_t> original = epee::to_span(slice);
+ const epee::byte_slice empty_slice = slice.take_slice(0);
+ EXPECT_EQ(original.begin(), slice.begin());
+ EXPECT_EQ(slice.begin(), slice.cbegin());
+ EXPECT_EQ(original.end(), slice.end());
+ EXPECT_EQ(slice.end(), slice.cend());
+
+ EXPECT_EQ(nullptr, empty_slice.begin());
+ EXPECT_EQ(nullptr, empty_slice.cbegin());
+ EXPECT_EQ(nullptr, empty_slice.end());
+ EXPECT_EQ(nullptr, empty_slice.cend());
+ EXPECT_EQ(nullptr, empty_slice.data());
+ EXPECT_TRUE(empty_slice.empty());
+ EXPECT_EQ(0u, empty_slice.size());
+
+ EXPECT_FALSE(slice.empty());
+ EXPECT_EQ(slice.cbegin(), slice.data());
+
const epee::byte_slice slice2 = slice.take_slice(remove_size);
EXPECT_EQ(original.begin() + remove_size, slice.begin());
@@ -809,6 +850,273 @@ TEST(ByteSlice, GetSlice)
EXPECT_TRUE(boost::range::equal(base_string, original));
}
+TEST(ByteStream, Construction)
+{
+ EXPECT_TRUE(std::is_default_constructible<epee::byte_stream>());
+ EXPECT_TRUE(std::is_move_constructible<epee::byte_stream>());
+ EXPECT_FALSE(std::is_copy_constructible<epee::byte_stream>());
+ EXPECT_TRUE(std::is_move_assignable<epee::byte_stream>());
+ EXPECT_FALSE(std::is_copy_assignable<epee::byte_stream>());
+}
+
+TEST(ByteStream, Noexcept)
+{
+ EXPECT_TRUE(std::is_nothrow_default_constructible<epee::byte_stream>());
+ EXPECT_TRUE(std::is_nothrow_move_constructible<epee::byte_stream>());
+ EXPECT_TRUE(std::is_nothrow_move_assignable<epee::byte_stream>());
+
+ epee::byte_stream lvalue;
+ const epee::byte_stream clvalue;
+
+ EXPECT_TRUE(noexcept(lvalue.data()));
+ EXPECT_TRUE(noexcept(clvalue.data()));
+ EXPECT_TRUE(noexcept(lvalue.tellp()));
+ EXPECT_TRUE(noexcept(clvalue.tellp()));
+ EXPECT_TRUE(noexcept(lvalue.available()));
+ EXPECT_TRUE(noexcept(clvalue.available()));
+ EXPECT_TRUE(noexcept(lvalue.size()));
+ EXPECT_TRUE(noexcept(clvalue.size()));
+ EXPECT_TRUE(noexcept(lvalue.capacity()));
+ EXPECT_TRUE(noexcept(clvalue.capacity()));
+ EXPECT_TRUE(noexcept(lvalue.put_unsafe(4)));
+ EXPECT_TRUE(noexcept(lvalue.take_buffer()));
+}
+
+TEST(ByteStream, Empty)
+{
+ epee::byte_stream stream;
+
+ EXPECT_EQ(epee::byte_stream::default_increase(), stream.increase_size());
+
+ EXPECT_EQ(nullptr, stream.data());
+ EXPECT_EQ(nullptr, stream.tellp());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(0u, stream.size());
+ EXPECT_EQ(0u, stream.capacity());
+
+ const auto buf = stream.take_buffer();
+ EXPECT_EQ(nullptr, buf.get());
+ EXPECT_EQ(nullptr, stream.data());
+ EXPECT_EQ(nullptr, stream.tellp());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(0u, stream.size());
+ EXPECT_EQ(0u, stream.capacity());
+}
+
+TEST(ByteStream, Write)
+{
+ using boost::range::equal;
+ using byte_span = epee::span<const std::uint8_t>;
+
+ static constexpr const std::uint8_t source[] =
+ {0xde, 0xad, 0xbe, 0xef, 0xef};
+
+ std::vector<std::uint8_t> bytes;
+ epee::byte_stream stream{4};
+
+ EXPECT_EQ(4u, stream.increase_size());
+
+ stream.write({source, 3});
+ bytes.insert(bytes.end(), source, source + 3);
+ EXPECT_EQ(3u, stream.size());
+ EXPECT_EQ(1u, stream.available());
+ EXPECT_EQ(4u, stream.capacity());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+
+ stream.write({source, 2});
+ bytes.insert(bytes.end(), source, source + 2);
+ EXPECT_EQ(5u, stream.size());
+ EXPECT_EQ(3u, stream.available());
+ EXPECT_EQ(8u, stream.capacity());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+
+ stream.write({source, 5});
+ bytes.insert(bytes.end(), source, source + 5);
+ EXPECT_EQ(10u, stream.size());
+ EXPECT_EQ(2u, stream.available());
+ EXPECT_EQ(12u, stream.capacity());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+
+ stream.write({source, 2});
+ bytes.insert(bytes.end(), source, source + 2);
+ EXPECT_EQ(12u, stream.size());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(12u, stream.capacity());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+
+ stream.write({source, 5});
+ bytes.insert(bytes.end(), source, source + 5);
+ EXPECT_EQ(17u, stream.size());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(17u, stream.capacity());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+}
+
+TEST(ByteStream, Put)
+{
+ using boost::range::equal;
+ using byte_span = epee::span<const std::uint8_t>;
+
+ std::vector<std::uint8_t> bytes;
+ epee::byte_stream stream;
+
+ for (std::uint8_t i = 0; i < 200; ++i)
+ {
+ bytes.push_back(i);
+ stream.put(i);
+ }
+
+ EXPECT_EQ(200u, stream.size());
+ EXPECT_EQ(epee::byte_stream::default_increase() - 200, stream.available());
+ EXPECT_EQ(epee::byte_stream::default_increase(), stream.capacity());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+}
+
+TEST(ByteStream, Reserve)
+{
+ using boost::range::equal;
+ using byte_span = epee::span<const std::uint8_t>;
+
+ static constexpr const std::uint8_t source[] =
+ {0xde, 0xad, 0xbe, 0xef, 0xef};
+
+ std::vector<std::uint8_t> bytes;
+ epee::byte_stream stream{4};
+
+ EXPECT_EQ(4u, stream.increase_size());
+
+ stream.reserve(100);
+ EXPECT_EQ(100u, stream.capacity());
+ EXPECT_EQ(0u, stream.size());
+ EXPECT_EQ(100u, stream.available());
+
+ for (std::size_t i = 0; i < 100 / sizeof(source); ++i)
+ {
+ stream.write(source);
+ bytes.insert(bytes.end(), source, source + sizeof(source));
+ }
+
+ EXPECT_EQ(100u, stream.size());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(100u, stream.capacity());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+}
+
+TEST(ByteStream, TakeBuffer)
+{
+ using boost::range::equal;
+ using byte_span = epee::span<const std::uint8_t>;
+
+ static constexpr const std::uint8_t source[] =
+ {0xde, 0xad, 0xbe, 0xef, 0xef};
+
+ epee::byte_stream stream;
+
+ stream.write(source);
+ ASSERT_EQ(sizeof(source), stream.size());
+ EXPECT_TRUE(equal(source, byte_span{stream.data(), stream.size()}));
+
+ const auto buffer = stream.take_buffer();
+ EXPECT_EQ(0u, stream.size());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(0u, stream.capacity());
+ EXPECT_EQ(nullptr, stream.data());
+ EXPECT_EQ(nullptr, stream.tellp());
+ EXPECT_TRUE(equal(source, byte_span{buffer.get(), sizeof(source)}));
+}
+
+TEST(ByteStream, Move)
+{
+ using boost::range::equal;
+ using byte_span = epee::span<const std::uint8_t>;
+
+ static constexpr const std::uint8_t source[] =
+ {0xde, 0xad, 0xbe, 0xef, 0xef};
+
+ epee::byte_stream stream{10};
+ stream.write(source);
+
+ epee::byte_stream stream2{std::move(stream)};
+
+ EXPECT_EQ(10u, stream.increase_size());
+ EXPECT_EQ(0u, stream.size());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(0u, stream.capacity());
+ EXPECT_EQ(nullptr, stream.data());
+ EXPECT_EQ(nullptr, stream.tellp());
+
+ EXPECT_EQ(10u, stream2.increase_size());
+ EXPECT_EQ(5u, stream2.size());
+ EXPECT_EQ(5u, stream2.available());
+ EXPECT_EQ(10u, stream2.capacity());
+ EXPECT_NE(nullptr, stream2.data());
+ EXPECT_NE(nullptr, stream2.tellp());
+ EXPECT_TRUE(equal(source, byte_span{stream2.data(), stream2.size()}));
+
+ stream = epee::byte_stream{};
+
+ EXPECT_EQ(epee::byte_stream::default_increase(), stream.increase_size());
+ EXPECT_EQ(0u, stream.size());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(0u, stream.capacity());
+ EXPECT_EQ(nullptr, stream.data());
+ EXPECT_EQ(nullptr, stream.tellp());
+
+ stream = std::move(stream2);
+
+ EXPECT_EQ(10u, stream.increase_size());
+ EXPECT_EQ(5u, stream.size());
+ EXPECT_EQ(5u, stream.available());
+ EXPECT_EQ(10u, stream.capacity());
+ EXPECT_NE(nullptr, stream.data());
+ EXPECT_NE(nullptr, stream.tellp());
+ EXPECT_TRUE(equal(source, byte_span{stream.data(), stream.size()}));
+
+ EXPECT_EQ(10u, stream2.increase_size());
+ EXPECT_EQ(0u, stream2.size());
+ EXPECT_EQ(0u, stream2.available());
+ EXPECT_EQ(0u, stream2.capacity());
+ EXPECT_EQ(nullptr, stream2.data());
+ EXPECT_EQ(nullptr, stream2.tellp());
+}
+
+TEST(ByteStream, ToByteSlice)
+{
+ using boost::range::equal;
+ using byte_span = epee::span<const std::uint8_t>;
+
+ static constexpr const std::uint8_t source[] =
+ {0xde, 0xad, 0xbe, 0xef, 0xef};
+
+ epee::byte_stream stream;
+
+ stream.write(source);
+ EXPECT_EQ(sizeof(source), stream.size());
+ EXPECT_TRUE(equal(source, byte_span{stream.data(), stream.size()}));
+
+ const epee::byte_slice slice{std::move(stream)};
+ EXPECT_EQ(0u, stream.size());
+ EXPECT_EQ(0u, stream.available());
+ EXPECT_EQ(0u, stream.capacity());
+ EXPECT_EQ(nullptr, stream.data());
+ EXPECT_EQ(nullptr, stream.tellp());
+ EXPECT_TRUE(equal(source, slice));
+
+ stream = epee::byte_stream{};
+ stream.reserve(1);
+ EXPECT_NE(nullptr, stream.data());
+ EXPECT_NE(nullptr, stream.tellp());
+
+ const epee::byte_slice empty_slice{std::move(stream)};
+ EXPECT_TRUE(empty_slice.empty());
+ EXPECT_EQ(0u, empty_slice.size());
+ EXPECT_EQ(nullptr, empty_slice.begin());
+ EXPECT_EQ(nullptr, empty_slice.cbegin());
+ EXPECT_EQ(nullptr, empty_slice.end());
+ EXPECT_EQ(nullptr, empty_slice.cend());
+ EXPECT_EQ(nullptr, empty_slice.data());
+}
+
TEST(ToHex, String)
{
EXPECT_TRUE(epee::to_hex::string(nullptr).empty());
diff --git a/tests/unit_tests/fee.cpp b/tests/unit_tests/fee.cpp
index 3b0bc1f09..d98b9e974 100644
--- a/tests/unit_tests/fee.cpp
+++ b/tests/unit_tests/fee.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/get_xtype_from_string.cpp b/tests/unit_tests/get_xtype_from_string.cpp
index 75452894a..78bbe6657 100644
--- a/tests/unit_tests/get_xtype_from_string.cpp
+++ b/tests/unit_tests/get_xtype_from_string.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index 1d1e8e9c0..6d7e9a8aa 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/hashchain.cpp b/tests/unit_tests/hashchain.cpp
index d07dfdb7a..5d85e960c 100644
--- a/tests/unit_tests/hashchain.cpp
+++ b/tests/unit_tests/hashchain.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/http.cpp b/tests/unit_tests/http.cpp
index 938f444d7..df3088a8b 100644
--- a/tests/unit_tests/http.cpp
+++ b/tests/unit_tests/http.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/json_serialization.cpp b/tests/unit_tests/json_serialization.cpp
index 6f98d854d..1db923f7b 100644
--- a/tests/unit_tests/json_serialization.cpp
+++ b/tests/unit_tests/json_serialization.cpp
@@ -3,10 +3,10 @@
#include <boost/range/adaptor/indexed.hpp>
#include <gtest/gtest.h>
#include <rapidjson/document.h>
-#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <vector>
+#include "byte_stream.h"
#include "crypto/hash.h"
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic.h"
@@ -15,7 +15,7 @@
#include "serialization/json_object.h"
-namespace
+namespace test
{
cryptonote::transaction
make_miner_transaction(cryptonote::account_public_address const& to)
@@ -82,18 +82,21 @@ namespace
return tx;
}
+}
+namespace
+{
template<typename T>
T test_json(const T& value)
{
- rapidjson::StringBuffer buffer;
+ epee::byte_stream buffer;
{
- rapidjson::Writer<rapidjson::StringBuffer> dest{buffer};
+ rapidjson::Writer<epee::byte_stream> dest{buffer};
cryptonote::json::toJsonValue(dest, value);
}
rapidjson::Document doc;
- doc.Parse(buffer.GetString());
+ doc.Parse(reinterpret_cast<const char*>(buffer.data()), buffer.size());
if (doc.HasParseError() || !doc.IsObject())
{
throw cryptonote::json::PARSE_FAIL();
@@ -109,7 +112,7 @@ TEST(JsonSerialization, MinerTransaction)
{
cryptonote::account_base acct;
acct.generate();
- const auto miner_tx = make_miner_transaction(acct.get_keys().m_account_address);
+ const auto miner_tx = test::make_miner_transaction(acct.get_keys().m_account_address);
crypto::hash tx_hash{};
ASSERT_TRUE(cryptonote::get_transaction_hash(miner_tx, tx_hash));
@@ -137,8 +140,8 @@ TEST(JsonSerialization, RegularTransaction)
cryptonote::account_base acct2;
acct2.generate();
- const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
- const auto tx = make_transaction(
+ const auto miner_tx = test::make_miner_transaction(acct1.get_keys().m_account_address);
+ const auto tx = test::make_transaction(
acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, false, false
);
@@ -168,8 +171,8 @@ TEST(JsonSerialization, RingctTransaction)
cryptonote::account_base acct2;
acct2.generate();
- const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
- const auto tx = make_transaction(
+ const auto miner_tx = test::make_miner_transaction(acct1.get_keys().m_account_address);
+ const auto tx = test::make_transaction(
acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, true, false
);
@@ -199,8 +202,8 @@ TEST(JsonSerialization, BulletproofTransaction)
cryptonote::account_base acct2;
acct2.generate();
- const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
- const auto tx = make_transaction(
+ const auto miner_tx = test::make_miner_transaction(acct1.get_keys().m_account_address);
+ const auto tx = test::make_transaction(
acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, true, true
);
diff --git a/tests/unit_tests/json_serialization.h b/tests/unit_tests/json_serialization.h
new file mode 100644
index 000000000..2d8267261
--- /dev/null
+++ b/tests/unit_tests/json_serialization.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+namespace test
+{
+ cryptonote::transaction make_miner_transaction(cryptonote::account_public_address const& to);
+
+ cryptonote::transaction
+ make_transaction(
+ cryptonote::account_keys const& from,
+ std::vector<cryptonote::transaction> const& sources,
+ std::vector<cryptonote::account_public_address> const& destinations,
+ bool rct,
+ bool bulletproof);
+}
diff --git a/tests/unit_tests/levin.cpp b/tests/unit_tests/levin.cpp
index d2ef920ef..15563e764 100644
--- a/tests/unit_tests/levin.cpp
+++ b/tests/unit_tests/levin.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -680,6 +680,76 @@ TEST_F(levin_notify, local_without_padding)
}
}
+TEST_F(levin_notify, forward_without_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'f');
+ txs[1].resize(200, 'e');
+
+ std::vector<cryptonote::blobdata> sorted_txs = txs;
+ std::sort(sorted_txs.begin(), sorted_txs.end());
+
+ ASSERT_EQ(10u, contexts_.size());
+ bool has_stemmed = false;
+ bool has_fluffed = false;
+ while (!has_stemmed || !has_fluffed)
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ const bool is_stem = events_.has_stem_txes();
+ EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
+
+ if (!is_stem)
+ {
+ notifier.run_fluff();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+
+ std::size_t send_count = 0;
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent && is_stem)
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ send_count += sent;
+ }
+
+ EXPECT_EQ(is_stem ? 1u : 9u, send_count);
+ ASSERT_EQ(is_stem ? 1u : 9u, receiver_.notified_size());
+ for (unsigned count = 0; count < (is_stem ? 1u : 9u); ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ if (is_stem)
+ EXPECT_EQ(txs, notification.txs);
+ else
+ EXPECT_EQ(sorted_txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
+ }
+
+ has_stemmed |= is_stem;
+ has_fluffed |= !is_stem;
+ notifier.run_epoch();
+ }
+}
+
TEST_F(levin_notify, block_without_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, false);
@@ -918,6 +988,73 @@ TEST_F(levin_notify, local_with_padding)
}
}
+TEST_F(levin_notify, forward_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ bool has_stemmed = false;
+ bool has_fluffed = false;
+ while (!has_stemmed || !has_fluffed)
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ const bool is_stem = events_.has_stem_txes();
+ EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
+
+ if (!is_stem)
+ {
+ notifier.run_fluff();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+
+ std::size_t send_count = 0;
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent && is_stem)
+ {
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ EXPECT_FALSE(context->is_incoming());
+ }
+ send_count += sent;
+ }
+
+ EXPECT_EQ(is_stem ? 1u : 9u, send_count);
+ ASSERT_EQ(is_stem ? 1u : 9u, receiver_.notified_size());
+ for (unsigned count = 0; count < (is_stem ? 1u : 9u); ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_FALSE(notification._.empty());
+ EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
+ }
+
+ has_stemmed |= is_stem;
+ has_fluffed |= !is_stem;
+ notifier.run_epoch();
+ }
+}
+
TEST_F(levin_notify, block_with_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, true);
@@ -1021,7 +1158,7 @@ TEST_F(levin_notify, private_fluff_without_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_TRUE(notification._.empty());
- EXPECT_FALSE(notification.dandelionpp_fluff);
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
@@ -1057,7 +1194,7 @@ TEST_F(levin_notify, private_stem_without_padding)
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
- EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
@@ -1072,7 +1209,7 @@ TEST_F(levin_notify, private_stem_without_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_TRUE(notification._.empty());
- EXPECT_FALSE(notification.dandelionpp_fluff);
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
@@ -1123,7 +1260,58 @@ TEST_F(levin_notify, private_local_without_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_TRUE(notification._.empty());
- EXPECT_FALSE(notification.dandelionpp_fluff);
+ EXPECT_TRUE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, private_forward_without_padding)
+{
+ // private mode always uses fluff but marked as stem
+ cryptonote::levin::notify notifier = make_notifier(0, false, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::forward));
+
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const bool is_incoming = ((context - contexts_.begin()) % 2 == 0);
+ EXPECT_EQ(is_incoming ? 0u : 1u, context->process_send_queue());
+ }
+
+ ASSERT_EQ(5u, receiver_.notified_size());
+ for (unsigned count = 0; count < 5; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
@@ -1233,7 +1421,7 @@ TEST_F(levin_notify, private_fluff_with_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_FALSE(notification._.empty());
- EXPECT_FALSE(notification.dandelionpp_fluff);
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
@@ -1268,7 +1456,7 @@ TEST_F(levin_notify, private_stem_with_padding)
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
- EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
@@ -1283,7 +1471,7 @@ TEST_F(levin_notify, private_stem_with_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_FALSE(notification._.empty());
- EXPECT_FALSE(notification.dandelionpp_fluff);
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
@@ -1333,7 +1521,57 @@ TEST_F(levin_notify, private_local_with_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_FALSE(notification._.empty());
- EXPECT_FALSE(notification.dandelionpp_fluff);
+ EXPECT_TRUE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, private_forward_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, false, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::forward));
+
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const bool is_incoming = ((context - contexts_.begin()) % 2 == 0);
+ EXPECT_EQ(is_incoming ? 0u : 1u, context->process_send_queue());
+ }
+
+ ASSERT_EQ(5u, receiver_.notified_size());
+ for (unsigned count = 0; count < 5; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_FALSE(notification._.empty());
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
diff --git a/tests/unit_tests/logging.cpp b/tests/unit_tests/logging.cpp
index c8526abae..b3afba243 100644
--- a/tests/unit_tests/logging.cpp
+++ b/tests/unit_tests/logging.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/long_term_block_weight.cpp b/tests/unit_tests/long_term_block_weight.cpp
index b7713c63a..f075034bd 100644
--- a/tests/unit_tests/long_term_block_weight.cpp
+++ b/tests/unit_tests/long_term_block_weight.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/main.cpp b/tests/unit_tests/main.cpp
index 76d17f2ad..ab14fee4e 100644
--- a/tests/unit_tests/main.cpp
+++ b/tests/unit_tests/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/memwipe.cpp b/tests/unit_tests/memwipe.cpp
index e0f5ada20..4f06b401e 100644
--- a/tests/unit_tests/memwipe.cpp
+++ b/tests/unit_tests/memwipe.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp
index 51feb54e4..0f9a81b46 100644
--- a/tests/unit_tests/mnemonics.cpp
+++ b/tests/unit_tests/mnemonics.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -49,9 +49,7 @@
#include "mnemonics/esperanto.h"
#include "mnemonics/lojban.h"
#include "mnemonics/english_old.h"
-#include "mnemonics/language_base.h"
#include "mnemonics/singleton.h"
-#include <boost/algorithm/string.hpp>
namespace
{
diff --git a/tests/unit_tests/mul_div.cpp b/tests/unit_tests/mul_div.cpp
index c1a72ce51..07f48f088 100644
--- a/tests/unit_tests/mul_div.cpp
+++ b/tests/unit_tests/mul_div.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp
index c5917200e..3171a64c1 100644
--- a/tests/unit_tests/multisig.cpp
+++ b/tests/unit_tests/multisig.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp
index b656c4858..588e91d02 100644
--- a/tests/unit_tests/node_server.cpp
+++ b/tests/unit_tests/node_server.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/output_selection.cpp b/tests/unit_tests/output_selection.cpp
index 0724cd3e0..cff509451 100644
--- a/tests/unit_tests/output_selection.cpp
+++ b/tests/unit_tests/output_selection.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/parse_amount.cpp b/tests/unit_tests/parse_amount.cpp
index f4f57f90f..b581f8dd2 100644
--- a/tests/unit_tests/parse_amount.cpp
+++ b/tests/unit_tests/parse_amount.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp
index 64fcbba4c..807bab64a 100644
--- a/tests/unit_tests/ringct.cpp
+++ b/tests/unit_tests/ringct.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/rolling_median.cpp b/tests/unit_tests/rolling_median.cpp
index 9e4cf87b8..730f1e7c5 100644
--- a/tests/unit_tests/rolling_median.cpp
+++ b/tests/unit_tests/rolling_median.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/rpc_version_str.cpp b/tests/unit_tests/rpc_version_str.cpp
index 5dce60465..249d297cf 100644
--- a/tests/unit_tests/rpc_version_str.cpp
+++ b/tests/unit_tests/rpc_version_str.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, The Monero Project
+// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index b711526e6..b460559ff 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -616,6 +616,46 @@ TEST(Serialization, serializes_ringct_types)
ASSERT_EQ(bp0, bp1);
}
+TEST(Serialization, key_encryption_transition)
+{
+ const cryptonote::network_type nettype = cryptonote::TESTNET;
+ tools::wallet2 w(nettype);
+ const boost::filesystem::path wallet_file = unit_test::data_dir / "wallet_9svHk1";
+ const boost::filesystem::path key_file = unit_test::data_dir / "wallet_9svHk1.keys";
+ const boost::filesystem::path temp_wallet_file = unit_test::data_dir / "wallet_9svHk1_temp";
+ const boost::filesystem::path temp_key_file = unit_test::data_dir / "wallet_9svHk1_temp.keys";
+ string password = "test";
+ bool r = false;
+
+ // Copy the original files for this test
+ boost::filesystem::copy(wallet_file,temp_wallet_file);
+ boost::filesystem::copy(key_file,temp_key_file);
+
+ try
+ {
+ // Key transition
+ w.load(temp_wallet_file.string(), password); // legacy decryption method
+ ASSERT_TRUE(w.get_load_info().is_legacy_key_encryption);
+ const crypto::secret_key view_secret_key = w.get_account().get_keys().m_view_secret_key;
+
+ w.rewrite(temp_wallet_file.string(), password); // transition to new key format
+
+ w.load(temp_wallet_file.string(), password); // new decryption method
+ ASSERT_FALSE(w.get_load_info().is_legacy_key_encryption);
+ ASSERT_EQ(w.get_account().get_keys().m_view_secret_key,view_secret_key);
+
+ r = true;
+ }
+ catch (const exception& e)
+ {}
+
+ // Remove the temporary files
+ boost::filesystem::remove(temp_wallet_file);
+ boost::filesystem::remove(temp_key_file);
+
+ ASSERT_TRUE(r);
+}
+
TEST(Serialization, portability_wallet)
{
const cryptonote::network_type nettype = cryptonote::TESTNET;
diff --git a/tests/unit_tests/sha256.cpp b/tests/unit_tests/sha256.cpp
index 898c9e4b3..0232511d4 100644
--- a/tests/unit_tests/sha256.cpp
+++ b/tests/unit_tests/sha256.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/slow_memmem.cpp b/tests/unit_tests/slow_memmem.cpp
index 4f13e00e6..602fdae38 100644
--- a/tests/unit_tests/slow_memmem.cpp
+++ b/tests/unit_tests/slow_memmem.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/subaddress.cpp b/tests/unit_tests/subaddress.cpp
index 385a2a8ab..bf24022e8 100644
--- a/tests/unit_tests/subaddress.cpp
+++ b/tests/unit_tests/subaddress.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/test_peerlist.cpp b/tests/unit_tests/test_peerlist.cpp
index dbb3aaf96..78404f9f9 100644
--- a/tests/unit_tests/test_peerlist.cpp
+++ b/tests/unit_tests/test_peerlist.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/test_protocol_pack.cpp b/tests/unit_tests/test_protocol_pack.cpp
index 59e46e332..312f18dfe 100644
--- a/tests/unit_tests/test_protocol_pack.cpp
+++ b/tests/unit_tests/test_protocol_pack.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/test_tx_utils.cpp b/tests/unit_tests/test_tx_utils.cpp
index deb45594d..9425e2432 100644
--- a/tests/unit_tests/test_tx_utils.cpp
+++ b/tests/unit_tests/test_tx_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/tx_proof.cpp b/tests/unit_tests/tx_proof.cpp
new file mode 100644
index 000000000..c5d06bc68
--- /dev/null
+++ b/tests/unit_tests/tx_proof.cpp
@@ -0,0 +1,130 @@
+// Copyright (c) 2018, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "gtest/gtest.h"
+
+#include "crypto/crypto.h"
+extern "C" {
+#include "crypto/crypto-ops.h"
+}
+#include "crypto/hash.h"
+#include <boost/algorithm/string.hpp>
+
+static inline unsigned char *operator &(crypto::ec_point &point) {
+ return &reinterpret_cast<unsigned char &>(point);
+ }
+
+static inline unsigned char *operator &(crypto::ec_scalar &scalar) {
+ return &reinterpret_cast<unsigned char &>(scalar);
+ }
+
+TEST(tx_proof, prove_verify_v2)
+{
+ crypto::secret_key r;
+ crypto::random32_unbiased(&r);
+
+ // A = aG
+ // B = bG
+ crypto::secret_key a,b;
+ crypto::public_key A,B;
+ crypto::generate_keys(A, a, a, false);
+ crypto::generate_keys(B, b, b, false);
+
+ // R_B = rB
+ crypto::public_key R_B;
+ ge_p3 B_p3;
+ ge_frombytes_vartime(&B_p3,&B);
+ ge_p2 R_B_p2;
+ ge_scalarmult(&R_B_p2, &unwrap(r), &B_p3);
+ ge_tobytes(&R_B, &R_B_p2);
+
+ // R_G = rG
+ crypto::public_key R_G;
+ ge_frombytes_vartime(&B_p3,&B);
+ ge_p3 R_G_p3;
+ ge_scalarmult_base(&R_G_p3, &unwrap(r));
+ ge_p3_tobytes(&R_G, &R_G_p3);
+
+ // D = rA
+ crypto::public_key D;
+ ge_p3 A_p3;
+ ge_frombytes_vartime(&A_p3,&A);
+ ge_p2 D_p2;
+ ge_scalarmult(&D_p2, &unwrap(r), &A_p3);
+ ge_tobytes(&D, &D_p2);
+
+ crypto::signature sig;
+
+ // Message data
+ crypto::hash prefix_hash;
+ char data[] = "hash input";
+ crypto::cn_fast_hash(data,sizeof(data)-1,prefix_hash);
+
+ // Generate/verify valid v1 proof with standard address
+ crypto::generate_tx_proof_v1(prefix_hash, R_G, A, boost::none, D, r, sig);
+ ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 1));
+
+ // Generate/verify valid v1 proof with subaddress
+ crypto::generate_tx_proof_v1(prefix_hash, R_B, A, B, D, r, sig);
+ ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 1));
+
+ // Generate/verify valid v2 proof with standard address
+ crypto::generate_tx_proof(prefix_hash, R_G, A, boost::none, D, r, sig);
+ ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 2));
+
+ // Generate/verify valid v2 proof with subaddress
+ crypto::generate_tx_proof(prefix_hash, R_B, A, B, D, r, sig);
+ ASSERT_TRUE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 2));
+
+ // Try to verify valid v2 proofs as v1 proof (bad)
+ crypto::generate_tx_proof(prefix_hash, R_G, A, boost::none, D, r, sig);
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 1));
+ crypto::generate_tx_proof(prefix_hash, R_B, A, B, D, r, sig);
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 1));
+
+ // Randomly-distributed test points
+ crypto::secret_key evil_a, evil_b, evil_d, evil_r;
+ crypto::public_key evil_A, evil_B, evil_D, evil_R;
+ crypto::generate_keys(evil_A, evil_a, evil_a, false);
+ crypto::generate_keys(evil_B, evil_b, evil_b, false);
+ crypto::generate_keys(evil_D, evil_d, evil_d, false);
+ crypto::generate_keys(evil_R, evil_r, evil_r, false);
+
+ // Selectively choose bad point in v2 proof (bad)
+ crypto::generate_tx_proof(prefix_hash, R_B, A, B, D, r, sig);
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, evil_R, A, B, D, sig, 2));
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, evil_A, B, D, sig, 2));
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, evil_B, D, sig, 2));
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, B, evil_D, sig, 2));
+
+ // Try to verify valid v1 proofs as v2 proof (bad)
+ crypto::generate_tx_proof_v1(prefix_hash, R_G, A, boost::none, D, r, sig);
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_G, A, boost::none, D, sig, 2));
+ crypto::generate_tx_proof_v1(prefix_hash, R_B, A, B, D, r, sig);
+ ASSERT_FALSE(crypto::check_tx_proof(prefix_hash, R_B, A, B, D, sig, 2));
+}
diff --git a/tests/unit_tests/unbound.cpp b/tests/unit_tests/unbound.cpp
index d122b2ad2..b404ca922 100644
--- a/tests/unit_tests/unbound.cpp
+++ b/tests/unit_tests/unbound.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/unit_tests_utils.h b/tests/unit_tests/unit_tests_utils.h
index 5944bd55a..1784ffb21 100644
--- a/tests/unit_tests/unit_tests_utils.h
+++ b/tests/unit_tests/unit_tests_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp
index 04d935751..83312a3c9 100644
--- a/tests/unit_tests/uri.cpp
+++ b/tests/unit_tests/uri.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019, The Monero Project
+// Copyright (c) 2016-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/varint.cpp b/tests/unit_tests/varint.cpp
index 72691d722..ca5af5ad2 100644
--- a/tests/unit_tests/varint.cpp
+++ b/tests/unit_tests/varint.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/vercmp.cpp b/tests/unit_tests/vercmp.cpp
index 77399fa89..90f4fdf79 100644
--- a/tests/unit_tests/vercmp.cpp
+++ b/tests/unit_tests/vercmp.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
diff --git a/tests/unit_tests/zmq_rpc.cpp b/tests/unit_tests/zmq_rpc.cpp
index af1f1608b..1d065fc45 100644
--- a/tests/unit_tests/zmq_rpc.cpp
+++ b/tests/unit_tests/zmq_rpc.cpp
@@ -26,11 +26,25 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <boost/preprocessor/stringize.hpp>
#include <gtest/gtest.h>
+#include <rapidjson/document.h>
+#include "cryptonote_basic/account.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "cryptonote_basic/events.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "json_serialization.h"
+#include "net/zmq.h"
#include "rpc/message.h"
+#include "rpc/zmq_pub.h"
+#include "rpc/zmq_server.h"
#include "serialization/json_object.h"
+#define MASSERT(...) \
+ if (!(__VA_ARGS__)) \
+ return testing::AssertionFailure() << BOOST_PP_STRINGIZE(__VA_ARGS__)
+
TEST(ZmqFullMessage, InvalidRequest)
{
EXPECT_THROW(
@@ -53,3 +67,711 @@ TEST(ZmqFullMessage, Request)
cryptonote::rpc::FullMessage parsed{request, true};
EXPECT_STREQ("foo", parsed.getRequestType().c_str());
}
+
+namespace
+{
+ using published_json = std::pair<std::string, rapidjson::Document>;
+
+ constexpr const char inproc_pub[] = "inproc://dummy_pub";
+
+ net::zmq::socket create_socket(void* ctx, const char* address)
+ {
+ net::zmq::socket sock{zmq_socket(ctx, ZMQ_PAIR)};
+ if (!sock)
+ MONERO_ZMQ_THROW("failed to create socket");
+ if (zmq_bind(sock.get(), address) != 0)
+ MONERO_ZMQ_THROW("socket bind failure");
+ return sock;
+ }
+
+ std::vector<std::string> get_messages(void* socket, int count = -1)
+ {
+ std::vector<std::string> out;
+ for ( ; count || count < 0; --count)
+ {
+ expect<std::string> next = net::zmq::receive(socket, (count < 0 ? ZMQ_DONTWAIT : 0));
+ if (next == net::zmq::make_error_code(EAGAIN))
+ return out;
+ out.push_back(std::move(*next));
+ }
+ return out;
+ }
+
+ std::vector<published_json> get_published(void* socket, int count = -1)
+ {
+ std::vector<published_json> out;
+
+ const auto messages = get_messages(socket, count);
+ out.reserve(messages.size());
+
+ for (const std::string& message : messages)
+ {
+ const char* split = std::strchr(message.c_str(), ':');
+ if (!split)
+ throw std::runtime_error{"Invalid ZMQ/Pub message"};
+
+ out.emplace_back();
+ out.back().first = {message.c_str(), split};
+ if (out.back().second.Parse(split + 1).HasParseError())
+ throw std::runtime_error{"Failed to parse ZMQ/Pub message"};
+ }
+
+ return out;
+ }
+
+ testing::AssertionResult compare_full_txpool(epee::span<const cryptonote::txpool_event> events, const published_json& pub)
+ {
+ MASSERT(pub.first == "json-full-txpool_add");
+ MASSERT(pub.second.IsArray());
+ MASSERT(pub.second.Size() <= events.size());
+
+ std::size_t i = 0;
+ for (const cryptonote::txpool_event& event : events)
+ {
+ MASSERT(i <= pub.second.Size());
+ if (!event.res)
+ continue;
+
+ cryptonote::transaction tx{};
+ cryptonote::json::fromJsonValue(pub.second[i], tx);
+
+ crypto::hash id{};
+ MASSERT(cryptonote::get_transaction_hash(event.tx, id));
+ MASSERT(cryptonote::get_transaction_hash(tx, id));
+ MASSERT(event.tx.hash == tx.hash);
+ ++i;
+ }
+ return testing::AssertionSuccess();
+ }
+
+ testing::AssertionResult compare_minimal_txpool(epee::span<const cryptonote::txpool_event> events, const published_json& pub)
+ {
+ MASSERT(pub.first == "json-minimal-txpool_add");
+ MASSERT(pub.second.IsArray());
+ MASSERT(pub.second.Size() <= events.size());
+
+ std::size_t i = 0;
+ for (const cryptonote::txpool_event& event : events)
+ {
+ MASSERT(i <= pub.second.Size());
+ if (!event.res)
+ continue;
+
+ std::size_t actual_size = 0;
+ crypto::hash actual_id{};
+
+ MASSERT(pub.second[i].IsObject());
+ GET_FROM_JSON_OBJECT(pub.second[i], actual_id, id);
+ GET_FROM_JSON_OBJECT(pub.second[i], actual_size, blob_size);
+
+ std::size_t expected_size = 0;
+ crypto::hash expected_id{};
+ MASSERT(cryptonote::get_transaction_hash(event.tx, expected_id, expected_size));
+ MASSERT(expected_size == actual_size);
+ MASSERT(expected_id == actual_id);
+ ++i;
+ }
+ return testing::AssertionSuccess();
+ }
+
+ testing::AssertionResult compare_full_block(const epee::span<const cryptonote::block> expected, const published_json& pub)
+ {
+ MASSERT(pub.first == "json-full-chain_main");
+ MASSERT(pub.second.IsArray());
+
+ std::vector<cryptonote::block> actual;
+ cryptonote::json::fromJsonValue(pub.second, actual);
+
+ MASSERT(expected.size() == actual.size());
+
+ for (std::size_t i = 0; i < expected.size(); ++i)
+ {
+ crypto::hash id;
+ MASSERT(cryptonote::get_block_hash(expected[i], id));
+ MASSERT(cryptonote::get_block_hash(actual[i], id));
+ MASSERT(expected[i].hash == actual[i].hash);
+ }
+
+ return testing::AssertionSuccess();
+ }
+
+ testing::AssertionResult compare_minimal_block(std::size_t height, const epee::span<const cryptonote::block> expected, const published_json& pub)
+ {
+ MASSERT(pub.first == "json-minimal-chain_main");
+ MASSERT(pub.second.IsObject());
+ MASSERT(!expected.empty());
+
+ std::size_t actual_height = 0;
+ crypto::hash actual_id{};
+ crypto::hash actual_prev_id{};
+ std::vector<crypto::hash> actual_ids{};
+ GET_FROM_JSON_OBJECT(pub.second, actual_height, first_height);
+ GET_FROM_JSON_OBJECT(pub.second, actual_prev_id, first_prev_id);
+ GET_FROM_JSON_OBJECT(pub.second, actual_ids, ids);
+
+ MASSERT(height == actual_height);
+ MASSERT(expected[0].prev_id == actual_prev_id);
+ MASSERT(expected.size() == actual_ids.size());
+
+ for (std::size_t i = 0; i < expected.size(); ++i)
+ {
+ crypto::hash id;
+ MASSERT(cryptonote::get_block_hash(expected[i], id));
+ MASSERT(id == actual_ids[i]);
+ }
+
+ return testing::AssertionSuccess();
+ }
+
+ struct zmq_base : public testing::Test
+ {
+ cryptonote::account_base acct;
+
+ zmq_base()
+ : testing::Test(), acct()
+ {
+ acct.generate();
+ }
+
+ cryptonote::transaction make_miner_transaction()
+ {
+ return test::make_miner_transaction(acct.get_keys().m_account_address);
+ }
+
+ cryptonote::transaction make_transaction(const std::vector<cryptonote::account_public_address>& destinations)
+ {
+ return test::make_transaction(acct.get_keys(), {make_miner_transaction()}, destinations, true, true);
+ }
+
+ cryptonote::transaction make_transaction()
+ {
+ cryptonote::account_base temp_account;
+ temp_account.generate();
+ return make_transaction({temp_account.get_keys().m_account_address});
+ }
+
+ cryptonote::block make_block()
+ {
+ cryptonote::block block{};
+ block.major_version = 1;
+ block.minor_version = 3;
+ block.timestamp = 100;
+ block.prev_id = crypto::rand<crypto::hash>();
+ block.nonce = 100;
+ block.miner_tx = make_miner_transaction();
+ return block;
+ }
+ };
+
+ struct zmq_pub : public zmq_base
+ {
+ net::zmq::context ctx;
+ net::zmq::socket relay;
+ net::zmq::socket dummy_pub;
+ net::zmq::socket dummy_client;
+ std::shared_ptr<cryptonote::listener::zmq_pub> pub;
+
+ zmq_pub()
+ : zmq_base(),
+ ctx(zmq_init(1)),
+ relay(create_socket(ctx.get(), cryptonote::listener::zmq_pub::relay_endpoint())),
+ dummy_pub(create_socket(ctx.get(), inproc_pub)),
+ dummy_client(zmq_socket(ctx.get(), ZMQ_PAIR)),
+ pub(std::make_shared<cryptonote::listener::zmq_pub>(ctx.get()))
+ {
+ if (!dummy_client)
+ MONERO_ZMQ_THROW("failed to create socket");
+ if (zmq_connect(dummy_client.get(), inproc_pub) != 0)
+ MONERO_ZMQ_THROW("failed to connect to dummy pub");
+ }
+
+ virtual void TearDown() override final
+ {
+ EXPECT_EQ(0u, get_messages(relay.get()).size());
+ EXPECT_EQ(0u, get_messages(dummy_client.get()).size());
+ }
+
+ template<std::size_t N>
+ bool sub_request(const char (&topic)[N])
+ {
+ return pub->sub_request({topic, N - 1});
+ }
+ };
+
+ struct dummy_handler final : cryptonote::rpc::RpcHandler
+ {
+ dummy_handler()
+ : cryptonote::rpc::RpcHandler()
+ {}
+
+ virtual epee::byte_slice handle(const std::string& request) override final
+ {
+ throw std::logic_error{"not implemented"};
+ }
+ };
+
+ struct zmq_server : public zmq_base
+ {
+ dummy_handler handler;
+ cryptonote::rpc::ZmqServer server;
+ std::shared_ptr<cryptonote::listener::zmq_pub> pub;
+ net::zmq::socket sub;
+
+ zmq_server()
+ : zmq_base(),
+ handler(),
+ server(handler),
+ pub(),
+ sub()
+ {
+ void* ctx = server.init_rpc({}, {});
+ if (!ctx)
+ throw std::runtime_error{"init_rpc failure"};
+
+ const std::string endpoint = inproc_pub;
+ pub = server.init_pub({std::addressof(endpoint), 1});
+ if (!pub)
+ throw std::runtime_error{"failed to initiaze zmq/pub"};
+
+ sub.reset(zmq_socket(ctx, ZMQ_SUB));
+ if (!sub)
+ MONERO_ZMQ_THROW("failed to create socket");
+ if (zmq_connect(sub.get(), inproc_pub) != 0)
+ MONERO_ZMQ_THROW("failed to connect to dummy pub");
+
+ server.run();
+ }
+
+ virtual void TearDown() override final
+ {
+ EXPECT_EQ(0u, get_messages(sub.get()).size());
+ sub.reset();
+ pub.reset();
+ server.stop();
+ }
+
+ template<std::size_t N>
+ void subscribe(const char (&topic)[N])
+ {
+ if (zmq_setsockopt(sub.get(), ZMQ_SUBSCRIBE, topic, N - 1) != 0)
+ MONERO_ZMQ_THROW("failed to subscribe");
+ }
+ };
+}
+
+TEST_F(zmq_pub, InvalidContext)
+{
+ EXPECT_THROW(cryptonote::listener::zmq_pub{nullptr}, std::logic_error);
+}
+
+TEST_F(zmq_pub, NoBlocking)
+{
+ EXPECT_FALSE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+}
+
+TEST_F(zmq_pub, DefaultDrop)
+{
+ EXPECT_EQ(0u, pub->send_txpool_add({{make_transaction(), {}, true}}));
+
+ const cryptonote::block bl = make_block();
+ EXPECT_EQ(0u,pub->send_chain_main(5, {std::addressof(bl), 1}));
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(5, {std::addressof(bl), 1}));
+}
+
+TEST_F(zmq_pub, JsonFullTxpool)
+{
+ static constexpr const char topic[] = "\1json-full-txpool_add";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ std::vector<cryptonote::txpool_event> events
+ {
+ {make_transaction(), {}, true}, {make_transaction(), {}, true}
+ };
+
+ EXPECT_NO_THROW(pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_EQ(1u, pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+}
+
+TEST_F(zmq_pub, JsonMinimalTxpool)
+{
+ static constexpr const char topic[] = "\1json-minimal-txpool_add";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ std::vector<cryptonote::txpool_event> events
+ {
+ {make_transaction(), {}, true}, {make_transaction(), {}, true}
+ };
+
+ EXPECT_NO_THROW(pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_EQ(1u, pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+}
+
+TEST_F(zmq_pub, JsonFullChain)
+{
+ static constexpr const char topic[] = "\1json-full-chain_main";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
+
+ EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
+}
+
+TEST_F(zmq_pub, JsonMinimalChain)
+{
+ static constexpr const char topic[] = "\1json-minimal-chain_main";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
+
+ EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_block(100, epee::to_span(blocks), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_block(533, epee::to_span(blocks), pubs.front()));
+}
+
+TEST_F(zmq_pub, JsonFullAll)
+{
+ static constexpr const char topic[] = "\1json-full";
+
+ ASSERT_TRUE(sub_request(topic));
+ {
+ std::vector<cryptonote::txpool_event> events
+ {
+ {make_transaction(), {}, true}, {make_transaction(), {}, true}
+ };
+
+ EXPECT_EQ(1u, pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_NO_THROW(pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+ }
+ {
+ const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
+
+ EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
+ }
+}
+
+TEST_F(zmq_pub, JsonMinimalAll)
+{
+ static constexpr const char topic[] = "\1json-minimal";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ {
+ std::vector<cryptonote::txpool_event> events
+ {
+ {make_transaction(), {}, true}, {make_transaction(), {}, true}
+ };
+
+ EXPECT_EQ(1u, pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_NO_THROW(pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+
+ events.at(0).res = false;
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+ }
+ {
+ const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
+
+ EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_block(100, epee::to_span(blocks), pubs.front()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(1u, pubs.size());
+ ASSERT_LE(1u, pubs.size());
+ EXPECT_TRUE(compare_minimal_block(533, epee::to_span(blocks), pubs.front()));
+ }
+}
+
+TEST_F(zmq_pub, JsonAll)
+{
+ static constexpr const char topic[] = "\1json";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ {
+ std::vector<cryptonote::txpool_event> events
+ {
+ {make_transaction(), {}, true}, {make_transaction(), {}, true}
+ };
+
+ EXPECT_EQ(1u, pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(2u, pubs.size());
+ ASSERT_LE(2u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(2u, pubs.size());
+ ASSERT_LE(2u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
+
+ events.at(0).res = false;
+ EXPECT_EQ(1u, pub->send_txpool_add(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(2u, pubs.size());
+ ASSERT_LE(2u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
+
+ events.at(0).res = false;
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(2u, pubs.size());
+ ASSERT_LE(2u, pubs.size());
+ EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
+ }
+ {
+ const std::array<cryptonote::block, 1> blocks{{make_block()}};
+
+ EXPECT_EQ(2u, pub->send_chain_main(100, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ auto pubs = get_published(dummy_client.get());
+ EXPECT_EQ(2u, pubs.size());
+ ASSERT_LE(2u, pubs.size());
+ EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
+ EXPECT_TRUE(compare_minimal_block(100, epee::to_span(blocks), pubs.back()));
+
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+ EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
+
+ pubs = get_published(dummy_client.get());
+ EXPECT_EQ(2u, pubs.size());
+ ASSERT_LE(2u, pubs.size());
+ EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
+ EXPECT_TRUE(compare_minimal_block(533, epee::to_span(blocks), pubs.back()));
+ }
+}
+
+TEST_F(zmq_pub, JsonChainWeakPtrSkip)
+{
+ static constexpr const char topic[] = "\1json";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ const std::array<cryptonote::block, 1> blocks{{make_block()}};
+
+ pub.reset();
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
+}
+
+TEST_F(zmq_pub, JsonTxpoolWeakPtrSkip)
+{
+ static constexpr const char topic[] = "\1json";
+
+ ASSERT_TRUE(sub_request(topic));
+
+ std::vector<cryptonote::txpool_event> events
+ {
+ {make_transaction(), {}, true}, {make_transaction(), {}, true}
+ };
+
+ pub.reset();
+ EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(std::move(events)));
+}
+
+TEST_F(zmq_server, pub)
+{
+ subscribe("json-minimal");
+
+ std::vector<cryptonote::txpool_event> events
+ {
+ {make_transaction(), {}, true}, {make_transaction(), {}, true}
+ };
+
+ const std::array<cryptonote::block, 1> blocks{{make_block()}};
+
+ ASSERT_EQ(1u, pub->send_txpool_add(events));
+ ASSERT_EQ(1u, pub->send_chain_main(200, epee::to_span(blocks)));
+
+ auto pubs = get_published(sub.get(), 2);
+ EXPECT_EQ(2u, pubs.size());
+ ASSERT_LE(2u, pubs.size());
+ EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
+ EXPECT_TRUE(compare_minimal_block(200, epee::to_span(blocks), pubs.back()));
+}
diff --git a/translations/CMakeLists.txt b/translations/CMakeLists.txt
index 589005a42..0081746f2 100644
--- a/translations/CMakeLists.txt
+++ b/translations/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019, The Monero Project
+# Copyright (c) 2017-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/translations/generate_translations_header.c b/translations/generate_translations_header.c
index 85e9b9b27..42248a184 100644
--- a/translations/generate_translations_header.c
+++ b/translations/generate_translations_header.c
@@ -1,5 +1,5 @@
// Copyright (c) 2013, Sergey Lyubka
-// Copyright (c) 2017-2019, The Monero Project
+// Copyright (c) 2017-2020, The Monero Project
// All rights reserved.
// Released under the MIT license.
diff --git a/utils/build_scripts/windows.bat b/utils/build_scripts/windows.bat
index 76d4f86bb..a90f27c0c 100644
--- a/utils/build_scripts/windows.bat
+++ b/utils/build_scripts/windows.bat
@@ -1,4 +1,4 @@
-:: Copyright (c) 2014-2019, The Monero Project
+:: Copyright (c) 2014-2020, The Monero Project
::
:: All rights reserved.
::
diff --git a/utils/gpg_keys/rbrunner7.asc b/utils/gpg_keys/rbrunner7.asc
new file mode 100644
index 000000000..5a3713e42
--- /dev/null
+++ b/utils/gpg_keys/rbrunner7.asc
@@ -0,0 +1,31 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBF6po6kBCADSKkQYShjqwMWKLv5EtBr92+3cbDBsqInmBUKbpznRmPaFVrE6
+h7rK1GrQJslddHM8amB75UPQv4kImU4EsHreoOwA0teKtKhYs53LbgZLg4D6A6Sh
+AxT4/e39lp+/Bjoi1slZTNwG7LVe0NQs0y9v2FgbZwTvxKX59rpDkQzQbCoP8Jxa
+E0eh1Yp3c7YHXnx6NUygS+tle9veehPQHDi6dPRfFp+Usk9Ojpws5PoBNdBsoNXH
+dRGRtKTgyD/FajwLatrJnGnL8NVzM0rMT05n1qsdZIWD/wKwgqmZCPbIJDZaC/QO
+AepIKWkPrWtJl6WVseDDTU7vMM0cHq+i0EmTABEBAAG0JlJlbsOpIEJydW5uZXIg
+PHJicnVubmVyQGRyZWFtc2hhcmUuY2g+iQFUBBMBCAA+FiEEn4wKfpzYWyxSK58w
+aiUdVx9/e8MFAl6po6kCGyMFCQPCE3cFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AA
+CgkQaiUdVx9/e8NVBAgAgPqN5VCpNy7Mnlu74LYbWX+uFihp5O2x5QaGP79KKXHj
++iiyKZLjk7fA1/XGg3zUlNOq5IGuQwFMWJICaEr6Ph7CoH+Zn9J5GG8QBACP7Rgy
+04+NqzgUlL1tGkLOsqUF0Vfhe1ux8g71OyDFDeo3YD1Jru/piwXoaHDxOZAbhwYj
+WXUuzghlS2GslF1I9BRoMQcQDFcLSX+l2sVCVtlkeIuqNHSFWhruOvBBEj9RwM8j
+Dm8h5shH62EEjr+KGuOiZJX/M9FRNk+qFMhfWWmXDmKc9CFV/ElAyXCSenEAzcV6
+ayXBjB1spHXRee7bOmLd/ku6qGbwpGp5aTBbNOPMV7kBDQReqaOpAQgA0PaRFp1s
+usThDLPc5/Xpy6H4m21LOyoF9VqLNQdVSIqqx8b5FqPjyTw3N957XXBvzAHdO0ig
+831tZb/JYU13jnUMnbtNHMwel+SNRWuqn+YU9/shN1B8Js///IwIFV2KCQKuQTRn
+ea2OPIlffdJYXPf0/BFWxr80Hb1EWkC6bpc1gsqrcGPzenVEV0PPdiAzsGWOzJkJ
+e69qgGLW2ulP7PUb8m4z7jXChzYQ1ki5t2BM7Ta30qWJ6qyvccOJxSAYDVHeT44q
+C83Vyeum/1n6isTlH1J6G760mX5/S3vIRfyE3eXjfOpluUf1kWScFuokUSFm+n7k
+BsHmzjjk9JuNlQARAQABiQE8BBgBCAAmFiEEn4wKfpzYWyxSK58waiUdVx9/e8MF
+Al6po6kCGwwFCQPCE3cACgkQaiUdVx9/e8NjCAgAjkMYw55h3fJj/wmyiF+G53uR
+kh6Z/07HKdFyhe+1698F49V68xWBMym56O5vv6iUBH4xBeyPTqC/nZ6v/L5m3z2F
+7f69hxaH7mp4BiLugcr2mkx8N6qCJBwSsVnql1/E5TvHWVjp00ikB5oYTRj7zcmo
+tLV9q2nBFjk5iWuoH5GtJ3PvIYZilIlqEqIF9trCD89sXZnATEI9Z8N+jFWAgYxQ
+f63xVHeW7vTA3ACyA7Qmf8XPjgDMlW4ANrgyGzmcZxGIpjNAlezBp/Bojw22Srrh
+uCRqoKg4lANxBJw9S6SO06QuKGJ7utIQ3YkqQFfzz47Q3sEvhLKvbSiBowazvw==
+=sdcD
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/utils/munin_plugins/alt_blocks_count b/utils/munin_plugins/alt_blocks_count
index 2510b7bc3..372f11088 100644
--- a/utils/munin_plugins/alt_blocks_count
+++ b/utils/munin_plugins/alt_blocks_count
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/difficulty b/utils/munin_plugins/difficulty
index a7d90c15f..02a307a02 100644
--- a/utils/munin_plugins/difficulty
+++ b/utils/munin_plugins/difficulty
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/grey_peerlist_size b/utils/munin_plugins/grey_peerlist_size
index b1cf66f14..3dad08150 100644
--- a/utils/munin_plugins/grey_peerlist_size
+++ b/utils/munin_plugins/grey_peerlist_size
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/height b/utils/munin_plugins/height
index 20b3e65ef..29c857817 100644
--- a/utils/munin_plugins/height
+++ b/utils/munin_plugins/height
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/incoming_connections_count b/utils/munin_plugins/incoming_connections_count
index 1dcc1f4d0..9c92749a3 100644
--- a/utils/munin_plugins/incoming_connections_count
+++ b/utils/munin_plugins/incoming_connections_count
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/outgoing_connections_count b/utils/munin_plugins/outgoing_connections_count
index 45a0500dd..277c02a15 100644
--- a/utils/munin_plugins/outgoing_connections_count
+++ b/utils/munin_plugins/outgoing_connections_count
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/tx_count b/utils/munin_plugins/tx_count
index e81e5f321..b61fe3b3d 100644
--- a/utils/munin_plugins/tx_count
+++ b/utils/munin_plugins/tx_count
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/tx_pool_size b/utils/munin_plugins/tx_pool_size
index 245733578..b8f81fbf6 100644
--- a/utils/munin_plugins/tx_pool_size
+++ b/utils/munin_plugins/tx_pool_size
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/munin_plugins/white_peerlist_size b/utils/munin_plugins/white_peerlist_size
index 8d87a9f0a..4cafb0fbc 100644
--- a/utils/munin_plugins/white_peerlist_size
+++ b/utils/munin_plugins/white_peerlist_size
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014-2019, The Monero Project
+# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
diff --git a/utils/systemd/monerod.service b/utils/systemd/monerod.service
index 5f37e54b2..dbb9e8aaa 100644
--- a/utils/systemd/monerod.service
+++ b/utils/systemd/monerod.service
@@ -7,6 +7,8 @@ User=monero
Group=monero
WorkingDirectory=~
RuntimeDirectory=monero
+StateDirectory=monero
+LogsDirectory=monero
# Clearnet config
#