From c9e8143b1cbe0ab461f5fd853e25b3c562e29669 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Thu, 26 Apr 2018 14:17:59 +0200 Subject: [PATCH 1/4] Merge branch 'sentinal_mode-2' into sentinel-squash --- CMakeLists.txt | 65 +--- rai/blockstore.hpp | 90 ++++- rai/common.cpp | 14 + rai/common.hpp | 6 +- rai/core_test/conflicts.cpp | 12 + rai/core_test/gap_cache.cpp | 9 +- rai/core_test/ledger.cpp | 27 +- rai/core_test/message.cpp | 12 +- rai/core_test/node.cpp | 87 +++-- rai/core_test/peer_container.cpp | 26 +- rai/core_test/rpc.cpp | 69 +++- rai/core_test/uint256_union.cpp | 24 ++ rai/core_test/wallet.cpp | 11 +- rai/ledger.cpp | 31 +- rai/ledger.hpp | 3 +- rai/lib/numbers.cpp | 2 +- rai/lib/work.cpp | 2 +- rai/node/bootstrap.cpp | 309 +++++++++-------- rai/node/bootstrap.hpp | 28 +- rai/node/common.cpp | 6 +- rai/node/node.cpp | 564 ++++++++++++++++++++----------- rai/node/node.hpp | 43 +-- rai/node/rpc.cpp | 100 +++++- rai/node/rpc.hpp | 1 + rai/node/wallet.cpp | 9 +- rai/qt/qt.cpp | 9 +- 26 files changed, 981 insertions(+), 578 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e016c11..ed8844f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,15 @@ cmake_minimum_required (VERSION 2.8.11) project (rai) -set (CPACK_PACKAGE_VERSION_MAJOR "11") -set (CPACK_PACKAGE_VERSION_MINOR "2") +set (CPACK_PACKAGE_VERSION_MAJOR "13") +set (CPACK_PACKAGE_VERSION_MINOR "0") set (CPACK_PACKAGE_VERSION_PATCH "0") if (DEFINED GIT_COMMIT) set (CPACK_PACKAGE_VERSION_PATCH "GIT-${GIT_COMMIT}") endif (DEFINED GIT_COMMIT) set (CPACK_PACKAGE_VENDOR "Nano Currency") -set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - -set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib:\$ORIGIN/") -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks") set (RAIBLOCKS_GUI OFF CACHE BOOL "") set (RAIBLOCKS_TEST OFF CACHE BOOL "") @@ -424,55 +421,15 @@ target_link_libraries (rai_node node secure lmdb ed25519 rai_lib_static argon2 $ set (CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE) if (RAIBLOCKS_GUI) if (APPLE) - get_filename_component (Qt5Core_framework_DIR ${Qt5_DIR}/../../QtCore.framework ABSOLUTE) - get_filename_component (Qt5Gui_framework_DIR ${Qt5_DIR}/../../QtGui.framework ABSOLUTE) - get_filename_component (Qt5PrintSupport_framework_DIR ${Qt5_DIR}/../../QtPrintSupport.framework ABSOLUTE) - get_filename_component (Qt5Test_framework_DIR ${Qt5_DIR}/../../QtTest.framework ABSOLUTE) - get_filename_component (Qt5Widgets_framework_DIR ${Qt5_DIR}/../../QtWidgets.framework ABSOLUTE) - get_filename_component (Qt5_platforms_DIR ${Qt5_DIR}/../../../plugins/platforms ABSOLUTE) - - file (COPY ${Qt5Core_framework_DIR} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/packaging) - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-id" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtCore.framework/Versions/5/QtCore") - - file (COPY ${Qt5Gui_framework_DIR} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/packaging) - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-id" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtGui.framework/Versions/5/QtGui") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Core_framework_DIR}/Versions/5/QtCore" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtGui.framework/Versions/5/QtGui") - - file (COPY ${Qt5PrintSupport_framework_DIR} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/packaging) - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-id" "@executable_path/../Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtPrintSupport.framework/Versions/5/QtPrintSupport") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Core_framework_DIR}/Versions/5/QtCore" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtPrintSupport.framework/Versions/5/QtPrintSupport") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Gui_framework_DIR}/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtPrintSupport.framework/Versions/5/QtPrintSupport") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Widgets_framework_DIR}/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtPrintSupport.framework/Versions/5/QtPrintSupport") - - file (COPY ${Qt5Test_framework_DIR} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/packaging) - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-id" "@executable_path/../Frameworks/QtTest.framework/Versions/5/QtTest" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtTest.framework/Versions/5/QtTest") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Core_framework_DIR}/Versions/5/QtCore" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtTest.framework/Versions/5/QtTest") - - file (COPY ${Qt5Widgets_framework_DIR} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/packaging) - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-id" "@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtWidgets.framework/Versions/5/QtWidgets") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Core_framework_DIR}/Versions/5/QtCore" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtWidgets.framework/Versions/5/QtWidgets") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Gui_framework_DIR}/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtWidgets.framework/Versions/5/QtWidgets") - - file (COPY ${Qt5_DIR}/../../../plugins/platforms/libqcocoa.dylib DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/packaging) - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Core_framework_DIR}/Versions/5/QtCore" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" "${CMAKE_CURRENT_BINARY_DIR}/packaging/libqcocoa.dylib") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Gui_framework_DIR}/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" "${CMAKE_CURRENT_BINARY_DIR}/packaging/libqcocoa.dylib") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5PrintSupport_framework_DIR}/Versions/5/QtPrintSupport" "@executable_path/../Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport" "${CMAKE_CURRENT_BINARY_DIR}/packaging/libqcocoa.dylib") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Widgets_framework_DIR}/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets" "${CMAKE_CURRENT_BINARY_DIR}/packaging/libqcocoa.dylib") - - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR}/packaging) - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Core_framework_DIR}/Versions/5/QtCore" "@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore" "${CMAKE_CURRENT_BINARY_DIR}/packaging/nano_wallet") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Gui_framework_DIR}/Versions/5/QtGui" "@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui" "${CMAKE_CURRENT_BINARY_DIR}/packaging/nano_wallet") - add_custom_command (TARGET nano_wallet POST_BUILD COMMAND "install_name_tool" "-change" "${Qt5Widgets_framework_DIR}/Versions/5/QtWidgets" "@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets" "${CMAKE_CURRENT_BINARY_DIR}/packaging/nano_wallet") - - install (FILES ${CMAKE_CURRENT_BINARY_DIR}/packaging/nano_wallet DESTINATION Nano.app/Contents/MacOS PERMISSIONS OWNER_EXECUTE OWNER_READ) + install (TARGETS nano_wallet DESTINATION Nano.app/Contents/MacOS) install (FILES Info.plist DESTINATION Nano.app/Contents) install (FILES qt.conf DESTINATION Nano.app/Contents/Resources) - install (DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtCore.framework" DESTINATION Nano.app/Contents/Frameworks USE_SOURCE_PERMISSIONS) - install (DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtGui.framework" DESTINATION Nano.app/Contents/Frameworks USE_SOURCE_PERMISSIONS) - install (DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtPrintSupport.framework" DESTINATION Nano.app/Contents/Frameworks USE_SOURCE_PERMISSIONS) - install (DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtTest.framework" DESTINATION Nano.app/Contents/Frameworks USE_SOURCE_PERMISSIONS) - install (DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/packaging/QtWidgets.framework" DESTINATION Nano.app/Contents/Frameworks USE_SOURCE_PERMISSIONS) - install (FILES "${CMAKE_CURRENT_BINARY_DIR}/packaging/libqcocoa.dylib" DESTINATION Nano.app/Contents/PlugIns/platforms PERMISSIONS OWNER_EXECUTE OWNER_READ) + install (DIRECTORY ${Qt5_DIR}/../../QtCore.framework DESTINATION Nano.app/Contents/Frameworks) + install (DIRECTORY ${Qt5_DIR}/../../QtGui.framework DESTINATION Nano.app/Contents/Frameworks) + install (DIRECTORY ${Qt5_DIR}/../../QtPrintSupport.framework DESTINATION Nano.app/Contents/Frameworks) + install (DIRECTORY ${Qt5_DIR}/../../QtTest.framework DESTINATION Nano.app/Contents/Frameworks) + install (DIRECTORY ${Qt5_DIR}/../../QtWidgets.framework DESTINATION Nano.app/Contents/Frameworks) + install (FILES "${Qt5_DIR}/../../../plugins/platforms/libqcocoa.dylib" DESTINATION Nano.app/Contents/PlugIns/platforms) install (FILES RaiBlocks.icns DESTINATION Nano.app/Contents/Resources) elseif (WIN32) if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") @@ -486,7 +443,7 @@ if (RAIBLOCKS_GUI) set (CPACK_PACKAGE_NAME "Nano_Installer") set (CPACK_NSIS_PACKAGE_NAME "Nano ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") set (CPACK_NSIS_URL_INFO_ABOUT "https://nano.org") - set (CPACK_NSIS_CONTACT "clemahieu@raiblocks.net") + set (CPACK_NSIS_CONTACT "info@nano.org") set (CPACK_NSIS_MENU_LINKS "nano_wallet.exe" "Nano Wallet" "https://nano.org" "Nano website") set (CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) get_target_property (Qt5WindowsPlugin Qt5::QWindowsIntegrationPlugin LOCATION) diff --git a/rai/blockstore.hpp b/rai/blockstore.hpp index 4a72fe19..281c5cdc 100644 --- a/rai/blockstore.hpp +++ b/rai/blockstore.hpp @@ -149,35 +149,95 @@ public: void clear (MDB_dbi); rai::mdb_env environment; - // block_hash -> account // Maps head blocks to owning account + + /** + * Maps head block to owning account + * rai::block_hash -> rai::account + */ MDB_dbi frontiers; - // account -> block_hash, representative, balance, timestamp // Account to head block, representative, balance, last_change + + /** + * Maps account to account information, head, rep, open, balance, timestamp and block count. + * rai::account -> rai::block_hash, rai::block_hash, rai::block_hash, rai::amount, uint64_t, uint64_t + */ MDB_dbi accounts; - // block_hash -> send_block + + /** + * Maps block hash to send block. + * rai::block_hash -> rai::send_block + */ MDB_dbi send_blocks; - // block_hash -> receive_block + + /** + * Maps block hash to receive block. + * rai::block_hash -> rai::receive_block + */ MDB_dbi receive_blocks; - // block_hash -> open_block + + /** + * Maps block hash to open block. + * rai::block_hash -> rai::open_block + */ MDB_dbi open_blocks; - // block_hash -> change_block + + /** + * Maps block hash to change block. + * rai::block_hash -> rai::change_block + */ MDB_dbi change_blocks; - // block_hash -> state_block + + /** + * Maps block hash to state block. + * rai::block_hash -> rai::state_block + */ MDB_dbi state_blocks; - // block_hash -> sender, amount, destination // Pending blocks to sender account, amount, destination account + + /** + * Maps (destination account, pending block) to (source account, amount). + * rai::account, rai::block_hash -> rai::account, rai::amount + */ MDB_dbi pending; - // block_hash -> account, balance // Blocks info + + /** + * Maps block hash to account and balance. + * block_hash -> rai::account, rai::amount + */ MDB_dbi blocks_info; - // account -> weight // Representation + + /** + * Representative weights. + * rai::account -> rai::uint128_t + */ MDB_dbi representation; - // block_hash -> block // Unchecked bootstrap blocks + + /** + * Unchecked bootstrap blocks. + * rai::block_hash -> rai::block + */ MDB_dbi unchecked; - // block_hash -> // Blocks that haven't been broadcast + + /** + * Blocks that haven't been broadcast. + * rai::block_hash -> (no value) + */ MDB_dbi unsynced; - // (uint56_t, uint8_t) -> block_hash // Mapping of region to checksum + + /** + * Mapping of region to checksum. + * (uint56_t, uint8_t) -> rai::block_hash + */ MDB_dbi checksum; - // account -> uint64_t // Highest vote observed for account + + /** + * Highest vote observed for account. + * rai::account -> uint64_t + */ MDB_dbi vote; - // uint256_union -> ? // Meta information about block store + + /** + * Meta information about block store, such as versions. + * rai::uint256_union (arbitrary key) -> blob + */ MDB_dbi meta; }; } diff --git a/rai/common.cpp b/rai/common.cpp index c39673cf..cf2f29e5 100644 --- a/rai/common.cpp +++ b/rai/common.cpp @@ -140,6 +140,20 @@ rai::tally_result rai::votes::vote (std::shared_ptr vote_a) return result; } +bool rai::votes::uncontested () +{ + bool result (true); + if (!rep_votes.empty ()) + { + auto block (rep_votes.begin ()->second); + for (auto i (rep_votes.begin ()), n (rep_votes.end ()); result && i != n; ++i) + { + result = *i->second == *block; + } + } + return result; +} + // Create a new random keypair rai::keypair::keypair () { diff --git a/rai/common.hpp b/rai/common.hpp index cddd5faf..7f9a48a8 100644 --- a/rai/common.hpp +++ b/rai/common.hpp @@ -23,6 +23,9 @@ struct hash } namespace rai { +const uint8_t protocol_version = 0x09; +const uint8_t protocol_version_min = 0x07; + class block_store; /** * Determine the balance as of this block @@ -125,7 +128,7 @@ public: }; /** - * Information on an uncollected send, source account, amount, target account. + * Information on an uncollected send */ class pending_info { @@ -249,6 +252,7 @@ class votes public: votes (std::shared_ptr); rai::tally_result vote (std::shared_ptr); + bool uncontested (); // Root block of fork rai::block_hash id; // All votes received by account diff --git a/rai/core_test/conflicts.cpp b/rai/core_test/conflicts.cpp index 13a6724a..621d66d8 100644 --- a/rai/core_test/conflicts.cpp +++ b/rai/core_test/conflicts.cpp @@ -75,3 +75,15 @@ TEST (conflicts, add_two) } ASSERT_EQ (2, node1.active.roots.size ()); } + +TEST (votes, contested) +{ + rai::genesis genesis; + auto block1 (std::make_shared (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0)); + auto block2 (std::make_shared (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - 2 * rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0)); + ASSERT_FALSE (*block1 == *block2); + rai::votes votes (block1); + ASSERT_TRUE (votes.uncontested ()); + votes.rep_votes[rai::test_genesis_key.pub] = block2; + ASSERT_FALSE (votes.uncontested ()); +} diff --git a/rai/core_test/gap_cache.cpp b/rai/core_test/gap_cache.cpp index 810de7f0..e6bfac07 100644 --- a/rai/core_test/gap_cache.cpp +++ b/rai/core_test/gap_cache.cpp @@ -85,11 +85,14 @@ TEST (gap_cache, two_dependencies) auto send2 (std::make_shared (send1->hash (), key.pub, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (send1->hash ()))); auto open (std::make_shared (send1->hash (), key.pub, key.pub, key.prv, key.pub, system.work.generate (key.pub))); ASSERT_EQ (0, system.nodes[0]->gap_cache.blocks.size ()); - system.nodes[0]->block_processor.process_receive_many (rai::block_processor_item (send2)); + system.nodes[0]->block_processor.add (send2); + system.nodes[0]->block_processor.flush (); ASSERT_EQ (1, system.nodes[0]->gap_cache.blocks.size ()); - system.nodes[0]->block_processor.process_receive_many (rai::block_processor_item (open)); + system.nodes[0]->block_processor.add (open); + system.nodes[0]->block_processor.flush (); ASSERT_EQ (2, system.nodes[0]->gap_cache.blocks.size ()); - system.nodes[0]->block_processor.process_receive_many (rai::block_processor_item (send1)); + system.nodes[0]->block_processor.add (send1); + system.nodes[0]->block_processor.flush (); ASSERT_EQ (0, system.nodes[0]->gap_cache.blocks.size ()); rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false); ASSERT_TRUE (system.nodes[0]->store.block_exists (transaction, send1->hash ())); diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 547d70c9..4a3e9865 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -985,6 +985,7 @@ TEST (ledger, successor) ASSERT_EQ (rai::process_result::progress, system.nodes[0]->ledger.process (transaction, send1).code); ASSERT_EQ (send1, *system.nodes[0]->ledger.successor (transaction, genesis.hash ())); ASSERT_EQ (*genesis.open, *system.nodes[0]->ledger.successor (transaction, genesis.open->root ())); + ASSERT_EQ (nullptr, system.nodes[0]->ledger.successor (transaction, 0)); } TEST (ledger, fail_change_old) @@ -1446,30 +1447,6 @@ TEST (ledger, latest_root) ASSERT_EQ (send.hash (), ledger.latest_root (transaction, rai::test_genesis_key.pub)); } -TEST (ledger, inactive_supply) -{ - bool init (false); - rai::block_store store (init, rai::unique_path ()); - ASSERT_TRUE (!init); - rai::ledger ledger (store, 40); - { - rai::transaction transaction (store.environment, nullptr, true); - rai::genesis genesis; - genesis.initialize (transaction, store); - rai::keypair key2; - rai::account_info info1; - ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info1)); - rai::send_block send (info1.head, key2.pub, std::numeric_limits::max () - 50, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); - ledger.process (transaction, send); - } - rai::transaction transaction (store.environment, nullptr, false); - ASSERT_EQ (10, ledger.supply (transaction)); - ledger.inactive_supply = 60; - ASSERT_EQ (0, ledger.supply (transaction)); - ledger.inactive_supply = 0; - ASSERT_EQ (50, ledger.supply (transaction)); -} - TEST (ledger, change_representative_move_representation) { bool init (false); @@ -2251,7 +2228,7 @@ TEST (ledger, state_canary_blocks) rai::genesis genesis; rai::send_block parse_canary (genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); rai::send_block generate_canary (parse_canary.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); - rai::ledger ledger (store, 0, parse_canary.hash (), generate_canary.hash ()); + rai::ledger ledger (store, parse_canary.hash (), generate_canary.hash ()); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::state_block state (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); diff --git a/rai/core_test/message.cpp b/rai/core_test/message.cpp index 2d886625..8bf0f378 100644 --- a/rai/core_test/message.cpp +++ b/rai/core_test/message.cpp @@ -54,9 +54,9 @@ TEST (message, publish_serialization) ASSERT_EQ (8, bytes.size ()); ASSERT_EQ (0x52, bytes[0]); ASSERT_EQ (0x41, bytes[1]); - ASSERT_EQ (0x07, bytes[2]); - ASSERT_EQ (0x07, bytes[3]); - ASSERT_EQ (0x01, bytes[4]); + ASSERT_EQ (rai::protocol_version, bytes[2]); + ASSERT_EQ (rai::protocol_version, bytes[3]); + ASSERT_EQ (rai::protocol_version_min, bytes[4]); ASSERT_EQ (static_cast (rai::message_type::publish), bytes[5]); ASSERT_EQ (0x02, bytes[6]); ASSERT_EQ (static_cast (rai::block_type::send), bytes[7]); @@ -67,9 +67,9 @@ TEST (message, publish_serialization) rai::message_type type; std::bitset<16> extensions; ASSERT_FALSE (rai::message::read_header (stream, version_max, version_using, version_min, type, extensions)); - ASSERT_EQ (0x01, version_min); - ASSERT_EQ (0x07, version_using); - ASSERT_EQ (0x07, version_max); + ASSERT_EQ (rai::protocol_version_min, version_min); + ASSERT_EQ (rai::protocol_version, version_using); + ASSERT_EQ (rai::protocol_version, version_max); ASSERT_EQ (rai::message_type::publish, type); } diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index fa35f223..ec44518f 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -27,21 +27,6 @@ TEST (node, block_store_path_failure) node->stop (); } -TEST (node, inactive_supply) -{ - rai::node_init init; - auto service (boost::make_shared ()); - rai::alarm alarm (*service); - auto path (rai::unique_path ()); - rai::node_config config; - config.logging.init (path); - rai::work_pool work (std::numeric_limits::max (), nullptr); - config.inactive_supply = 10; - auto node (std::make_shared (init, *service, path, alarm, config, work)); - ASSERT_EQ (10, node->ledger.inactive_supply); - node->stop (); -} - TEST (node, state_canaries) { rai::node_init init; @@ -505,7 +490,8 @@ TEST (node_config, serialization) rai::node_config config1 (100, logging1); config1.bootstrap_fraction_numerator = 10; config1.receive_minimum = 10; - config1.inactive_supply = 10; + config1.online_weight_minimum = 10; + config1.online_weight_quorom = 10; config1.password_fanout = 10; config1.enable_voting = false; config1.callback_address = "test"; @@ -523,7 +509,8 @@ TEST (node_config, serialization) ASSERT_NE (config2.bootstrap_fraction_numerator, config1.bootstrap_fraction_numerator); ASSERT_NE (config2.peering_port, config1.peering_port); ASSERT_NE (config2.logging.node_lifetime_tracing_value, config1.logging.node_lifetime_tracing_value); - ASSERT_NE (config2.inactive_supply, config1.inactive_supply); + ASSERT_NE (config2.online_weight_minimum, config1.online_weight_minimum); + ASSERT_NE (config2.online_weight_quorom, config1.online_weight_quorom); ASSERT_NE (config2.password_fanout, config1.password_fanout); ASSERT_NE (config2.enable_voting, config1.enable_voting); ASSERT_NE (config2.callback_address, config1.callback_address); @@ -539,7 +526,8 @@ TEST (node_config, serialization) ASSERT_EQ (config2.bootstrap_fraction_numerator, config1.bootstrap_fraction_numerator); ASSERT_EQ (config2.peering_port, config1.peering_port); ASSERT_EQ (config2.logging.node_lifetime_tracing_value, config1.logging.node_lifetime_tracing_value); - ASSERT_EQ (config2.inactive_supply, config1.inactive_supply); + ASSERT_EQ (config2.online_weight_minimum, config1.online_weight_minimum); + ASSERT_EQ (config2.online_weight_quorom, config1.online_weight_quorom); ASSERT_EQ (config2.password_fanout, config1.password_fanout); ASSERT_EQ (config2.enable_voting, config1.enable_voting); ASSERT_EQ (config2.callback_address, config1.callback_address); @@ -650,7 +638,7 @@ TEST (node_config, v2_v3_upgrade) ASSERT_FALSE (tree.get_optional ("io_threads")); ASSERT_FALSE (tree.get_optional ("work_threads")); config1.deserialize_json (upgraded, tree); - ASSERT_EQ (rai::uint128_union (0).to_string_dec (), tree.get ("inactive_supply")); + //ASSERT_EQ (rai::uint128_union (0).to_string_dec (), tree.get ("inactive_supply")); ASSERT_EQ ("1024", tree.get ("password_fanout")); ASSERT_NE (0, std::stoul (tree.get ("password_fanout"))); ASSERT_NE (0, std::stoul (tree.get ("password_fanout"))); @@ -896,9 +884,9 @@ TEST (node, DISABLED_fork_bootstrap_flip) rai::keypair key2; auto send2 (std::make_shared (latest, key2.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system0.work.generate (latest))); // Insert but don't rebroadcast, simulating settled blocks - node1.block_processor.process_receive_many (rai::block_processor_item (send1)); + node1.block_processor.add (send1); node1.block_processor.flush (); - node2.block_processor.process_receive_many (rai::block_processor_item (send2)); + node2.block_processor.add (send2); node2.block_processor.flush (); { rai::transaction transaction (node2.store.environment, nullptr, false); @@ -1012,7 +1000,7 @@ TEST (node, coherent_observer) { rai::system system (24000, 1); auto & node1 (*system.nodes[0]); - node1.observers.blocks.add ([&node1](std::shared_ptr block_a, rai::process_return const &) { + node1.observers.blocks.add ([&node1](std::shared_ptr block_a, rai::account const &, rai::uint128_t const &, bool) { rai::transaction transaction (node1.store.environment, nullptr, false); ASSERT_TRUE (node1.store.block_exists (transaction, block_a->hash ())); }); @@ -1445,7 +1433,7 @@ TEST (node, bootstrap_connection_scaling) rai::system system (24000, 1); auto & node1 (*system.nodes[0]); node1.bootstrap_initiator.bootstrap (); - auto & attempt = node1.bootstrap_initiator.attempt; + auto attempt (node1.bootstrap_initiator.current_attempt ()); ASSERT_EQ (34, attempt->target_connections (25000)); ASSERT_EQ (4, attempt->target_connections (0)); ASSERT_EQ (64, attempt->target_connections (50000)); @@ -1475,3 +1463,56 @@ TEST (node, online_reps) ASSERT_LT (iterations, 200); } } + +TEST (node, block_confirm) +{ + rai::system system (24000, 1); + rai::genesis genesis; + system.nodes[0]->ledger.state_block_parse_canary = genesis.hash (); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + auto send1 (std::make_shared (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.nodes[0]->generate_work (genesis.hash ()))); + { + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, true); + ASSERT_EQ (rai::process_result::progress, system.nodes[0]->ledger.process (transaction, *send1).code); + } + system.nodes[0]->block_confirm (send1); + ASSERT_TRUE (system.nodes[0]->active.confirmed.empty ()); + auto iterations (0); + while (system.nodes[0]->active.confirmed.empty ()) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } +} + +TEST (node, confirm_quorom) +{ + rai::system system (24000, 1); + rai::genesis genesis; + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.nodes [0]->ledger.state_block_parse_canary = genesis.hash (); + // Put greater than online_weight_minimum in pending so quorom can't be reached + auto send1 (std::make_shared (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.nodes[0]->generate_work (genesis.hash ()))); + { + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, true); + ASSERT_EQ (rai::process_result::progress, system.nodes[0]->ledger.process (transaction, *send1).code); + } + system.wallet (0)->send_action (rai::test_genesis_key.pub, rai::test_genesis_key.pub, rai::Gxrb_ratio); + auto iterations (0); + while (system.nodes[0]->active.roots.empty ()) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } + ASSERT_FALSE (system.nodes[0]->active.roots.empty ()); + while (!system.nodes[0]->active.roots.empty ()) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } + ASSERT_TRUE (system.nodes[0]->active.roots.empty ()); + ASSERT_EQ (0, system.nodes[0]->balance (rai::test_genesis_key.pub)); +} diff --git a/rai/core_test/peer_container.cpp b/rai/core_test/peer_container.cpp index e99e9914..a0e24185 100644 --- a/rai/core_test/peer_container.cpp +++ b/rai/core_test/peer_container.cpp @@ -17,9 +17,9 @@ TEST (peer_container, no_recontact) ASSERT_EQ (0, peers.size ()); peers.peer_observer = [&observed_peer](rai::endpoint const &) { ++observed_peer; }; peers.disconnect_observer = [&observed_disconnect]() { observed_disconnect = true; }; - ASSERT_FALSE (peers.insert (endpoint1, 0)); + ASSERT_FALSE (peers.insert (endpoint1, rai::protocol_version)); ASSERT_EQ (1, peers.size ()); - ASSERT_TRUE (peers.insert (endpoint1, 0)); + ASSERT_TRUE (peers.insert (endpoint1, rai::protocol_version)); auto remaining (peers.purge_list (std::chrono::steady_clock::now () + std::chrono::seconds (5))); ASSERT_TRUE (remaining.empty ()); ASSERT_EQ (1, observed_peer); @@ -115,7 +115,7 @@ TEST (peer_container, list_sqrt) ASSERT_TRUE (list1.empty ()); for (auto i (0); i < 1000; ++i) { - ASSERT_FALSE (peers.insert (rai::endpoint (boost::asio::ip::address_v6::loopback (), 10000 + i), 0)); + ASSERT_FALSE (peers.insert (rai::endpoint (boost::asio::ip::address_v6::loopback (), 10000 + i), rai::protocol_version)); } auto list2 (peers.list_sqrt ()); ASSERT_EQ (64, list2.size ()); @@ -130,13 +130,15 @@ TEST (peer_container, rep_weight) rai::endpoint endpoint1 (boost::asio::ip::address_v6::loopback (), 24002); rai::endpoint endpoint2 (boost::asio::ip::address_v6::loopback (), 24003); rai::amount amount (100); - peers.insert (endpoint2, 0); - peers.insert (endpoint0, 0); - peers.insert (endpoint1, 0); - peers.rep_response (endpoint0, amount); + peers.insert (endpoint2, rai::protocol_version); + peers.insert (endpoint0, rai::protocol_version); + peers.insert (endpoint1, rai::protocol_version); + rai::keypair keypair; + peers.rep_response (endpoint0, keypair.pub, amount); auto reps (peers.representatives (1)); ASSERT_EQ (1, reps.size ()); ASSERT_EQ (100, reps[0].rep_weight.number ()); + ASSERT_EQ (keypair.pub, reps[0].probable_rep_account); ASSERT_EQ (endpoint0, reps[0].endpoint); } @@ -146,7 +148,7 @@ TEST (peer_container, reachout) rai::peer_container peers (rai::endpoint{}); rai::endpoint endpoint0 (boost::asio::ip::address_v6::loopback (), 24000); // Make sure having been contacted by them already indicates we shouldn't reach out - peers.contacted (endpoint0, 0); + peers.contacted (endpoint0, rai::protocol_version); ASSERT_TRUE (peers.reachout (endpoint0)); rai::endpoint endpoint1 (boost::asio::ip::address_v6::loopback (), 24001); ASSERT_FALSE (peers.reachout (endpoint1)); @@ -159,3 +161,11 @@ TEST (peer_container, reachout) peers.purge_list (std::chrono::steady_clock::now () + std::chrono::seconds (10)); ASSERT_FALSE (peers.reachout (endpoint1)); } + +TEST (peer_container, depeer) +{ + rai::peer_container peers (rai::endpoint{}); + rai::endpoint endpoint0 (boost::asio::ip::address_v6::loopback (), 24000); + peers.contacted (endpoint0, rai::protocol_version_min - 1); + ASSERT_EQ (0, peers.size ()); +} diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index 97879f6f..813dbfe1 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -1005,7 +1005,7 @@ TEST (rpc, process_block_no_work) system.poll (); } ASSERT_EQ (200, response.status); - ASSERT_FALSE (response.json.get ("error").empty ()); + ASSERT_FALSE (response.json.get ("error", "").empty ()); } TEST (rpc, keepalive) @@ -1134,7 +1134,7 @@ TEST (rpc, payment_end_nonempty) system.poll (); } ASSERT_EQ (200, response1.status); - ASSERT_FALSE (response1.json.get ("error").empty ()); + ASSERT_FALSE (response1.json.get ("error", "").empty ()); } TEST (rpc, payment_zero_balance) @@ -1234,7 +1234,7 @@ TEST (rpc, payment_begin_locked) system.poll (); } ASSERT_EQ (200, response1.status); - ASSERT_FALSE (response1.json.get ("error").empty ()); + ASSERT_FALSE (response1.json.get ("error", "").empty ()); } TEST (rpc, payment_wait) @@ -1284,7 +1284,7 @@ TEST (rpc, payment_wait) TEST (rpc, peers) { rai::system system (24000, 2); - system.nodes[0]->peers.insert (rai::endpoint (boost::asio::ip::address_v6::from_string ("::ffff:80.80.80.80"), 4000), 1); + system.nodes[0]->peers.insert (rai::endpoint (boost::asio::ip::address_v6::from_string ("::ffff:80.80.80.80"), 4000), rai::protocol_version); rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); rpc.start (); boost::property_tree::ptree request; @@ -2842,10 +2842,13 @@ TEST (rpc, blocks_info) ASSERT_FALSE (pending.is_initialized ()); boost::optional source (blocks.second.get_optional ("source_account")); ASSERT_FALSE (source.is_initialized ()); + boost::optional balance (blocks.second.get_optional ("balance")); + ASSERT_FALSE (balance.is_initialized ()); } // Test for optional values request.put ("source", "true"); request.put ("pending", "1"); + request.put ("balance", "true"); test_response response2 (request, rpc, system.service); while (response2.status == 0) { @@ -2858,6 +2861,8 @@ TEST (rpc, blocks_info) ASSERT_EQ ("0", source); std::string pending (blocks.second.get ("pending")); ASSERT_EQ ("0", pending); + std::string balance_text (blocks.second.get ("balance")); + ASSERT_EQ (rai::genesis_amount.convert_to (), balance_text); } } @@ -2879,7 +2884,7 @@ TEST (rpc, work_peers_all) system.poll (); } ASSERT_EQ (200, response.status); - std::string success (response.json.get ("success")); + std::string success (response.json.get ("success", "")); ASSERT_TRUE (success.empty ()); boost::property_tree::ptree request1; request1.put ("action", "work_peers"); @@ -2905,7 +2910,7 @@ TEST (rpc, work_peers_all) system.poll (); } ASSERT_EQ (200, response2.status); - success = response2.json.get ("success"); + success = response2.json.get ("success", ""); ASSERT_TRUE (success.empty ()); test_response response3 (request1, rpc, system.service); while (response3.status == 0) @@ -3119,14 +3124,6 @@ TEST (rpc, block_create) rai::change_block change (open.hash (), key.pub, key.prv, key.pub, change_work); request1.put ("type", "change"); request1.put ("work", rai::to_string_hex (change_work)); - test_response response3 (request1, rpc, system.service); - while (response3.status == 0) - { - system.poll (); - } - ASSERT_EQ (200, response3.status); - ASSERT_FALSE (response3.json.get ("error").empty ()); // error with missing previous block - request1.put ("previous", open.hash ().to_string ()); test_response response4 (request1, rpc, system.service); while (response4.status == 0) { @@ -3512,3 +3509,47 @@ TEST (rpc, confirmation_history) ASSERT_EQ ((rai::genesis_amount - rai::Gxrb_ratio).convert_to (), tally); system.stop (); } + +TEST (rpc, block_confirm) +{ + rai::system system (24000, 1); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + rai::genesis genesis; + system.nodes[0]->ledger.state_block_parse_canary = genesis.hash (); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + auto send1 (std::make_shared (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.nodes[0]->generate_work (genesis.hash ()))); + { + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, true); + ASSERT_EQ (rai::process_result::progress, system.nodes[0]->ledger.process (transaction, *send1).code); + } + rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "block_confirm"); + request.put ("hash", send1->hash ().to_string ()); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + ASSERT_EQ ("1", response.json.get ("started")); +} + +TEST (rpc, block_confirm_absent) +{ + rai::system system (24000, 1); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "block_confirm"); + request.put ("hash", "0"); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + ASSERT_EQ ("Block not found", response.json.get ("error")); +} diff --git a/rai/core_test/uint256_union.cpp b/rai/core_test/uint256_union.cpp index 79090e2d..cffe1e82 100644 --- a/rai/core_test/uint256_union.cpp +++ b/rai/core_test/uint256_union.cpp @@ -314,6 +314,30 @@ TEST (uint256_union, decode_account_v1) ASSERT_EQ (rai::rai_test_account, key); } +TEST (uint256_union, decode_account_variations) +{ + for (int i = 0; i < 100; i++) + { + rai::raw_key key; + xrb_generate_random (key.data.bytes.data ()); + rai::uint256_union pub; + xrb_key_account (key.data.bytes.data (), pub.bytes.data ()); + + char account[65] = { 0 }; + xrb_uint256_to_address (pub.bytes.data (), account); + + // Replace first digit after xrb_ with '0'..'9', make sure only one of them is valid + int errors = 0; + for (int variation = 0; variation < 10; variation++) + { + account[4] = static_cast (variation + 48); + errors += xrb_valid_address (account); + } + + ASSERT_EQ (errors, 9); + } +} + TEST (uint256_union, account_transcode) { rai::uint256_union value; diff --git a/rai/core_test/wallet.cpp b/rai/core_test/wallet.cpp index b5ed11ba..65d5f29e 100644 --- a/rai/core_test/wallet.cpp +++ b/rai/core_test/wallet.cpp @@ -869,17 +869,10 @@ TEST (wallet, send_race) rai::system system (24000, 1); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); rai::keypair key2; - system.nodes[0]->block_processor.stop (); + for (auto i (1); i < 60; ++i) { ASSERT_NE (nullptr, system.wallet (0)->send_action (rai::test_genesis_key.pub, key2.pub, rai::Gxrb_ratio)); - ASSERT_NE (nullptr, system.wallet (0)->send_action (rai::test_genesis_key.pub, key2.pub, rai::Gxrb_ratio)); - } - auto iterations (0); - while (system.nodes[0]->balance (rai::test_genesis_key.pub) != rai::genesis_amount - rai::Gxrb_ratio * 2) - { - system.poll (); - ++iterations; - ASSERT_LT (iterations, 200); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio * i, system.nodes[0]->balance (rai::test_genesis_key.pub)); } } diff --git a/rai/ledger.cpp b/rai/ledger.cpp index bd88cd11..845990bf 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -209,7 +209,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a) if (result.code == rai::process_result::progress) { is_send = block_a.hashables.balance < info.balance; - result.amount = result.amount.number () - info.balance.number (); + result.amount = is_send ? (info.balance.number () - result.amount.number ()) : (result.amount.number () - info.balance.number ()); result.code = block_a.hashables.previous == info.head ? rai::process_result::progress : rai::process_result::fork; // Is the previous block the account's head block? (Ambigious) } } @@ -264,7 +264,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a) if (is_send) { rai::pending_key key (block_a.hashables.link, hash); - rai::pending_info info (block_a.hashables.account, 0 - result.amount.number ()); + rai::pending_info info (block_a.hashables.account, result.amount.number ()); ledger.store.pending_put (transaction, key, info); } else if (!block_a.hashables.link.is_zero ()) @@ -495,9 +495,8 @@ bool rai::shared_ptr_block_hash::operator() (std::shared_ptr const & return *lhs == *rhs; } -rai::ledger::ledger (rai::block_store & store_a, rai::uint128_t const & inactive_supply_a, rai::block_hash const & state_block_parse_canary_a, rai::block_hash const & state_block_generate_canary_a) : +rai::ledger::ledger (rai::block_store & store_a, rai::block_hash const & state_block_parse_canary_a, rai::block_hash const & state_block_generate_canary_a) : store (store_a), -inactive_supply (inactive_supply_a), check_bootstrap_weights (true), state_block_parse_canary (state_block_parse_canary_a), state_block_generate_canary (state_block_generate_canary_a) @@ -583,8 +582,7 @@ rai::uint128_t rai::ledger::supply (MDB_txn * transaction_a) auto unallocated (account_balance (transaction_a, rai::genesis_account)); auto burned (account_pending (transaction_a, 0)); auto absolute_supply (rai::genesis_amount - unallocated - burned); - auto adjusted_supply (absolute_supply - inactive_supply); - return adjusted_supply <= absolute_supply ? adjusted_supply : 0; + return absolute_supply; } rai::block_hash rai::ledger::representative (MDB_txn * transaction_a, rai::block_hash const & hash_a) @@ -849,25 +847,26 @@ void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & a } } -std::unique_ptr rai::ledger::successor (MDB_txn * transaction_a, rai::block_hash const & block_a) +std::unique_ptr rai::ledger::successor (MDB_txn * transaction_a, rai::uint256_union const & root_a) { - assert (store.account_exists (transaction_a, block_a) || store.block_exists (transaction_a, block_a)); - assert (store.account_exists (transaction_a, block_a) || latest (transaction_a, account (transaction_a, block_a)) != block_a); - rai::block_hash successor; - if (store.account_exists (transaction_a, block_a)) + rai::block_hash successor (0); + if (store.account_exists (transaction_a, root_a)) { rai::account_info info; - auto error (store.account_get (transaction_a, block_a, info)); + auto error (store.account_get (transaction_a, root_a, info)); assert (!error); successor = info.open_block; } else { - successor = store.block_successor (transaction_a, block_a); + successor = store.block_successor (transaction_a, root_a); } - assert (!successor.is_zero ()); - auto result (store.block_get (transaction_a, successor)); - assert (result != nullptr); + std::unique_ptr result; + if (!successor.is_zero ()) + { + result = store.block_get (transaction_a, successor); + } + assert (successor.is_zero () || result != nullptr); return result; } diff --git a/rai/ledger.hpp b/rai/ledger.hpp index 6d199282..402f645e 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -16,7 +16,7 @@ public: class ledger { public: - ledger (rai::block_store &, rai::uint128_t const & = 0, rai::block_hash const & = 0, rai::block_hash const & = 0); + ledger (rai::block_store &, rai::block_hash const & = 0, rai::block_hash const & = 0); std::pair> winner (MDB_txn *, rai::votes const & votes_a); // Map of weight -> associated block, ordered greatest to least std::map, std::greater> tally (MDB_txn *, rai::votes const &); @@ -49,7 +49,6 @@ public: bool state_block_generation_enabled (MDB_txn *); static rai::uint128_t const unit; rai::block_store & store; - rai::uint128_t inactive_supply; std::unordered_map bootstrap_weights; uint64_t bootstrap_weight_max_blocks; std::atomic check_bootstrap_weights; diff --git a/rai/lib/numbers.cpp b/rai/lib/numbers.cpp index e2aee857..9b3f22dc 100644 --- a/rai/lib/numbers.cpp +++ b/rai/lib/numbers.cpp @@ -118,7 +118,7 @@ bool rai::uint256_union::decode_account (std::string const & source_a) auto error (source_a.size () != 64); if (!error) { - if (source_a[0] == 'x' && source_a[1] == 'r' && source_a[2] == 'b' && (source_a[3] == '_' || source_a[3] == '-')) + if (source_a[0] == 'x' && source_a[1] == 'r' && source_a[2] == 'b' && (source_a[3] == '_' || source_a[3] == '-') && (source_a[4] == '1' || source_a[4] == '3')) { rai::uint512_t number_l; for (auto i (source_a.begin () + 4), j (source_a.end ()); !error && i != j; ++i) diff --git a/rai/lib/work.cpp b/rai/lib/work.cpp index a0998f6a..63f71d54 100644 --- a/rai/lib/work.cpp +++ b/rai/lib/work.cpp @@ -32,7 +32,7 @@ done (false), opencl (opencl_a) { static_assert (ATOMIC_INT_LOCK_FREE == 2, "Atomic int needed"); - auto count (rai::rai_network == rai::rai_networks::rai_test_network ? 1 : std::max (1u, std::min (max_threads_a, std::thread::hardware_concurrency ()))); + auto count (rai::rai_network == rai::rai_networks::rai_test_network ? 1 : std::min (max_threads_a, std::max (1u, std::thread::hardware_concurrency ()))); for (auto i (0); i < count; ++i) { auto thread (std::thread ([this, i]() { diff --git a/rai/node/bootstrap.cpp b/rai/node/bootstrap.cpp index a500c99b..83f6151e 100644 --- a/rai/node/bootstrap.cpp +++ b/rai/node/bootstrap.cpp @@ -13,6 +13,36 @@ constexpr unsigned bootstrap_frontier_retry_limit = 16; constexpr double bootstrap_minimum_termination_time_sec = 30.0; constexpr unsigned bootstrap_max_new_connections = 10; +rai::socket_timeout::socket_timeout (rai::bootstrap_client & client_a) : +ticket (0), +client (client_a) +{ +} + +void rai::socket_timeout::start (std::chrono::steady_clock::time_point timeout_a) +{ + auto ticket_l (++ticket); + std::weak_ptr client_w (client.shared ()); + client.node->alarm.add (timeout_a, [client_w, ticket_l]() { + if (auto client_l = client_w.lock ()) + { + if (client_l->timeout.ticket == ticket_l) + { + client_l->socket.close (); + if (client_l->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (client_l->node->log) << boost::str (boost::format ("Disconnecting from %1% due to timeout") % client_l->socket.remote_endpoint ()); + } + } + } + }); +} + +void rai::socket_timeout::stop () +{ + ++ticket; +} + rai::block_synchronization::block_synchronization (boost::log::sources::logger_mt & log_a) : log (log_a) { @@ -170,11 +200,11 @@ rai::bootstrap_client::bootstrap_client (std::shared_ptr node_a, std: node (node_a), attempt (attempt_a), socket (node_a->service), +timeout (*this), endpoint (endpoint_a), -timeout (node_a->service), +start_time (std::chrono::steady_clock::now ()), block_count (0), pending_stop (false), -start_time (std::chrono::steady_clock::now ()), hard_stop (false) { ++attempt->connections; @@ -207,28 +237,12 @@ void rai::bootstrap_client::stop (bool force) void rai::bootstrap_client::start_timeout () { - timeout.expires_from_now (boost::posix_time::seconds (5)); - std::weak_ptr this_w (shared ()); - timeout.async_wait ([this_w](boost::system::error_code const & ec) { - if (ec != boost::asio::error::operation_aborted) - { - auto this_l (this_w.lock ()); - if (this_l != nullptr) - { - this_l->socket.close (); - if (this_l->node->config.logging.bulk_pull_logging ()) - { - BOOST_LOG (this_l->node->log) << boost::str (boost::format ("Disconnecting from %1% due to timeout") % this_l->endpoint); - } - } - } - }); + timeout.start (std::chrono::steady_clock::now () + std::chrono::seconds (5)); } void rai::bootstrap_client::stop_timeout () { - size_t killed (timeout.cancel ()); - (void)killed; + timeout.stop (); } void rai::bootstrap_client::run () @@ -239,7 +253,10 @@ void rai::bootstrap_client::run () this_l->stop_timeout (); if (!ec) { - BOOST_LOG (this_l->node->log) << boost::str (boost::format ("Connection established to %1%") % this_l->endpoint); + if (this_l->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (this_l->node->log) << boost::str (boost::format ("Connection established to %1%") % this_l->endpoint); + } this_l->attempt->pool_connection (this_l->shared_from_this ()); } else @@ -249,11 +266,13 @@ void rai::bootstrap_client::run () switch (ec.value ()) { default: - BOOST_LOG (this_l->node->log) << boost::str (boost::format ("Error initiating bootstrap connection to %2%: %1%") % ec.message () % this_l->endpoint); + BOOST_LOG (this_l->node->log) << boost::str (boost::format ("Error initiating bootstrap connection to %1%: %2%") % this_l->endpoint % ec.message ()); break; case boost::system::errc::connection_refused: case boost::system::errc::operation_canceled: case boost::system::errc::timed_out: + case 995: //Windows The I/O operation has been aborted because of either a thread exit or an application request + case 10061: //Windows No connection could be made because the target machine actively refused it break; } } @@ -298,8 +317,7 @@ std::shared_ptr rai::bootstrap_client::shared () rai::frontier_req_client::frontier_req_client (std::shared_ptr connection_a) : connection (connection_a), current (0), -count (0), -next_report (std::chrono::steady_clock::now () + std::chrono::seconds (15)) +count (0) { rai::transaction transaction (connection->node->store.environment, nullptr, false); next (transaction); @@ -325,7 +343,10 @@ void rai::frontier_req_client::receive_frontier () } else { - BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Invalid size: expected %1%, got %2%") % size_l % size_a); + if (this_l->connection->node->config.logging.network_message_logging ()) + { + BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Invalid size: expected %1%, got %2%") % size_l % size_a); + } } }); } @@ -368,10 +389,8 @@ void rai::frontier_req_client::received_frontier (boost::system::error_code cons promise.set_value (true); return; } - auto now (std::chrono::steady_clock::now ()); - if (next_report < now) + if (connection->attempt->should_log ()) { - next_report = now + std::chrono::seconds (15); BOOST_LOG (connection->node->log) << boost::str (boost::format ("Received %1% frontiers from %2%") % std::to_string (count) % connection->socket.remote_endpoint ()); } if (!account.is_zero ()) @@ -473,10 +492,9 @@ void rai::frontier_req_client::next (MDB_txn * transaction_a) } } -rai::bulk_pull_client::bulk_pull_client (std::shared_ptr connection_a, rai::pull_info const & pull_a, size_t size_a) : +rai::bulk_pull_client::bulk_pull_client (std::shared_ptr connection_a, rai::pull_info const & pull_a) : connection (connection_a), -pull (pull_a), -size (size_a) +pull (pull_a) { std::lock_guard mutex (connection->attempt->mutex); ++connection->attempt->pulling; @@ -513,11 +531,13 @@ void rai::bulk_pull_client::request () } if (connection->node->config.logging.bulk_pull_logging ()) { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Requesting account %1% from %2%. %3% accounts in queue") % req.start.to_account () % connection->endpoint % size); + std::unique_lock lock (connection->attempt->mutex); + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Requesting account %1% from %2%. %3% accounts in queue") % req.start.to_account () % connection->endpoint % connection->attempt->pulls.size ()); } - else if (connection->node->config.logging.network_logging () && connection->attempt->account_count++ % 256 == 0) + else if (connection->node->config.logging.network_logging () && connection->attempt->should_log ()) { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Requesting account %1% from %2%. %3% accounts in queue") % req.start.to_account () % connection->endpoint % size); + std::unique_lock lock (connection->attempt->mutex); + BOOST_LOG (connection->node->log) << boost::str (boost::format ("%1% accounts in pull queue") % connection->attempt->pulls.size ()); } auto this_l (shared_from_this ()); connection->start_timeout (); @@ -529,7 +549,10 @@ void rai::bulk_pull_client::request () } else { - BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error sending bulk pull request %1% to %2%") % ec.message () % this_l->connection->endpoint); + if (this_l->connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error sending bulk pull request to %1%: to %2%") % ec.message () % this_l->connection->endpoint); + } } }); } @@ -546,7 +569,10 @@ void rai::bulk_pull_client::receive_block () } else { - BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error receiving block type %1%") % ec.message ()); + if (this_l->connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error receiving block type: %1%") % ec.message ()); + } } }); } @@ -613,7 +639,10 @@ void rai::bulk_pull_client::received_type () } default: { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Unknown type received as block type: %1%") % static_cast (type)); + if (connection->node->config.logging.network_packet_logging ()) + { + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Unknown type received as block type: %1%") % static_cast (type)); + } break; } } @@ -643,7 +672,7 @@ void rai::bulk_pull_client::received_block (boost::system::error_code const & ec connection->start_time = std::chrono::steady_clock::now (); } connection->attempt->total_blocks++; - connection->attempt->node->block_processor.add (rai::block_processor_item (block)); + connection->attempt->node->block_processor.add (block); if (!connection->hard_stop.load ()) { receive_block (); @@ -651,12 +680,18 @@ void rai::bulk_pull_client::received_block (boost::system::error_code const & ec } else { - BOOST_LOG (connection->node->log) << "Error deserializing block received from pull request"; + if (connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (connection->node->log) << "Error deserializing block received from pull request"; + } } } else { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Error bulk receiving block: %1%") % ec.message ()); + if (connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Error bulk receiving block: %1%") % ec.message ()); + } } } @@ -692,7 +727,10 @@ void rai::bulk_push_client::start () } else { - BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Unable to send bulk_push request %1%") % ec.message ()); + if (this_l->connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Unable to send bulk_push request: %1%") % ec.message ()); + } } }); } @@ -772,7 +810,10 @@ void rai::bulk_push_client::push_block (rai::block const & block_a) } else { - BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error sending block during bulk push %1%") % ec.message ()); + if (this_l->connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error sending block during bulk push: %1%") % ec.message ()); + } } }); } @@ -793,6 +834,7 @@ attempts (0) } rai::bootstrap_attempt::bootstrap_attempt (std::shared_ptr node_a) : +next_log (std::chrono::steady_clock::now ()), connections (0), pulling (0), node (node_a), @@ -810,6 +852,19 @@ rai::bootstrap_attempt::~bootstrap_attempt () node->bootstrap_initiator.notify_listeners (false); } +bool rai::bootstrap_attempt::should_log () +{ + std::lock_guard lock (mutex); + auto result (false); + auto now (std::chrono::steady_clock::now ()); + if (next_log < now) + { + result = true; + next_log = now + std::chrono::seconds (15); + } + return result; +} + bool rai::bootstrap_attempt::request_frontier (std::unique_lock & lock_a) { auto result (true); @@ -856,8 +911,8 @@ void rai::bootstrap_attempt::request_pull (std::unique_lock & lock_a auto size (pulls.size ()); // The bulk_pull_client destructor attempt to requeue_pull which can cause a deadlock if this is the last reference // Dispatch request in an external thread in case it needs to be destroyed - node->background ([connection_l, pull, size]() { - auto client (std::make_shared (connection_l, pull, size)); + node->background ([connection_l, pull]() { + auto client (std::make_shared (connection_l, pull)); client->request (); }); } @@ -897,14 +952,12 @@ bool rai::bootstrap_attempt::still_pulling () auto running (!stopped); auto more_pulls (!pulls.empty ()); auto still_pulling (pulling > 0); - auto more_forks (!unresolved_forks.empty ()); - return running && (more_pulls || still_pulling || more_forks); + return running && (more_pulls || still_pulling); } void rai::bootstrap_attempt::run () { populate_connections (); - resolve_forks (); std::unique_lock lock (mutex); auto frontier_failure (true); while (!stopped && frontier_failure) @@ -982,61 +1035,34 @@ bool rai::bootstrap_attempt::consume_future (std::future & future_a) void rai::bootstrap_attempt::process_fork (MDB_txn * transaction_a, std::shared_ptr block_a) { - try_resolve_fork (transaction_a, block_a, true); -} - -void rai::bootstrap_attempt::try_resolve_fork (MDB_txn * transaction_a, std::shared_ptr block_a, bool from_processor) -{ - std::weak_ptr this_w (shared_from_this ()); - if (!node->store.block_exists (transaction_a, block_a->hash ()) && (node->store.block_exists (transaction_a, block_a->root ()) || node->store.account_exists (transaction_a, block_a->root ()))) + std::lock_guard lock (mutex); + auto root (block_a->root ()); + if (!node->store.block_exists (transaction_a, block_a->hash ()) && (node->store.block_exists (transaction_a, root) || node->store.account_exists (transaction_a, root))) { std::shared_ptr ledger_block (node->ledger.forked_block (transaction_a, *block_a)); if (ledger_block) { - node->active.start (transaction_a, ledger_block, [this_w, block_a](std::shared_ptr, bool resolved) { - if (auto this_l = this_w.lock ()) - { - if (resolved) - { - { - std::unique_lock lock (this_l->mutex); - this_l->unresolved_forks.erase (block_a->hash ()); - this_l->condition.notify_all (); - } - rai::transaction transaction (this_l->node->store.environment, nullptr, false); - auto account (this_l->node->ledger.store.frontier_get (transaction, block_a->root ())); - if (!account.is_zero ()) - { - this_l->requeue_pull (rai::pull_info (account, block_a->root (), block_a->root ())); - } - else if (this_l->node->ledger.store.account_exists (transaction, block_a->root ())) - { - this_l->requeue_pull (rai::pull_info (block_a->root (), rai::block_hash (0), rai::block_hash (0))); - } - } - } - }); - - auto hash = block_a->hash (); - bool exists = true; - if (from_processor) + std::weak_ptr this_w (shared_from_this ()); + if (!node->active.start (transaction_a, std::make_pair (ledger_block, block_a), [this_w, root](std::shared_ptr, bool resolved) { + if (auto this_l = this_w.lock ()) + { + if (resolved) + { + rai::transaction transaction (this_l->node->store.environment, nullptr, false); + auto account (this_l->node->ledger.store.frontier_get (transaction, root)); + if (!account.is_zero ()) + { + this_l->requeue_pull (rai::pull_info (account, root, root)); + } + else if (this_l->node->ledger.store.account_exists (transaction, root)) + { + this_l->requeue_pull (rai::pull_info (root, rai::block_hash (0), rai::block_hash (0))); + } + } + } + })) { - // Only add the block to the unresolved fork tracker if it's the first time we've seen it (i.e. this call came from the block processor). - std::unique_lock lock (mutex); - exists = unresolved_forks.find (hash) != unresolved_forks.end (); - if (!exists) - { - unresolved_forks[hash] = block_a; - } - } - - if (!exists) - { - BOOST_LOG (node->log) << boost::str (boost::format ("While bootstrappping, fork between our block: %1% and block %2% both with root %3%") % ledger_block->hash ().to_string () % hash.to_string () % block_a->root ().to_string ()); - } - if (!exists || !from_processor) - { - // Only broadcast if it's a new fork, or if the request is coming from the retry loop. + BOOST_LOG (node->log) << boost::str (boost::format ("Resolving fork between our block: %1% and block %2% both with root %3%") % ledger_block->hash ().to_string () % block_a->hash ().to_string () % block_a->root ().to_string ()); node->network.broadcast_confirm_req (ledger_block); node->network.broadcast_confirm_req (block_a); } @@ -1044,39 +1070,6 @@ void rai::bootstrap_attempt::try_resolve_fork (MDB_txn * transaction_a, std::sha } } -void rai::bootstrap_attempt::resolve_forks () -{ - std::unordered_map> forks_to_resolve; - { - std::unique_lock lock (mutex); - forks_to_resolve = unresolved_forks; - } - - if (forks_to_resolve.size () > 0) - { - BOOST_LOG (node->log) << boost::str (boost::format ("%1% unresolved forks while bootstrapping") % forks_to_resolve.size ()); - rai::transaction transaction (node->store.environment, nullptr, false); - for (auto & it : forks_to_resolve) - { - try_resolve_fork (transaction, it.second, false); - } - } - - { - std::unique_lock lock (mutex); - if (!stopped) - { - std::weak_ptr this_w (shared_from_this ()); - node->alarm.add (std::chrono::steady_clock::now () + std::chrono::seconds (30), [this_w]() { - if (auto this_l = this_w.lock ()) - { - this_l->resolve_forks (); - } - }); - } - } -} - struct block_rate_cmp { bool operator() (const std::shared_ptr & lhs, const std::shared_ptr & rhs) const @@ -1271,8 +1264,8 @@ void rai::bootstrap_attempt::requeue_pull (rai::pull_info const & pull_a) if (auto connection_shared = connection_frontier_request.lock ()) { auto size (pulls.size ()); - node->background ([connection_shared, pull, size]() { - auto client (std::make_shared (connection_shared, pull, size)); + node->background ([connection_shared, pull]() { + auto client (std::make_shared (connection_shared, pull)); client->request (); }); if (node->config.logging.bulk_pull_logging ()) @@ -1315,7 +1308,7 @@ void rai::bootstrap_initiator::bootstrap () void rai::bootstrap_initiator::bootstrap (rai::endpoint const & endpoint_a) { - node.peers.insert (endpoint_a, 0x5); + node.peers.insert (endpoint_a, rai::protocol_version); std::unique_lock lock (mutex); if (!stopped) { @@ -1357,9 +1350,14 @@ void rai::bootstrap_initiator::add_observer (std::function const & o } bool rai::bootstrap_initiator::in_progress () +{ + return current_attempt () != nullptr; +} + +std::shared_ptr rai::bootstrap_initiator::current_attempt () { std::lock_guard lock (mutex); - return attempt != nullptr; + return attempt; } void rai::bootstrap_initiator::stop () @@ -1551,7 +1549,7 @@ void rai::bootstrap_server::receive_header_action (boost::system::error_code con { if (node->config.logging.bulk_pull_logging ()) { - BOOST_LOG (node->log) << boost::str (boost::format ("Error while receiving type %1%") % ec.message ()); + BOOST_LOG (node->log) << boost::str (boost::format ("Error while receiving type: %1%") % ec.message ()); } } } @@ -1615,7 +1613,7 @@ void rai::bootstrap_server::receive_frontier_req_action (boost::system::error_co { if (node->config.logging.network_logging ()) { - BOOST_LOG (node->log) << boost::str (boost::format ("Error sending receiving frontier request %1%") % ec.message ()); + BOOST_LOG (node->log) << boost::str (boost::format ("Error sending receiving frontier request: %1%") % ec.message ()); } } } @@ -1806,7 +1804,10 @@ void rai::bulk_pull_server::sent_action (boost::system::error_code const & ec, s } else { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Unable to bulk send block: %1%") % ec.message ()); + if (connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Unable to bulk send block: %1%") % ec.message ()); + } } } @@ -1833,7 +1834,10 @@ void rai::bulk_pull_server::no_block_sent (boost::system::error_code const & ec, } else { - BOOST_LOG (connection->node->log) << "Unable to send not-a-block"; + if (connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (connection->node->log) << "Unable to send not-a-block"; + } } } @@ -1986,7 +1990,10 @@ void rai::bulk_pull_blocks_server::sent_action (boost::system::error_code const } else { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Unable to bulk send block: %1%") % ec.message ()); + if (connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Unable to bulk send block: %1%") % ec.message ()); + } } } @@ -2013,7 +2020,10 @@ void rai::bulk_pull_blocks_server::no_block_sent (boost::system::error_code cons } else { - BOOST_LOG (connection->node->log) << "Unable to send not-a-block"; + if (connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (connection->node->log) << "Unable to send not-a-block"; + } } } @@ -2043,7 +2053,10 @@ void rai::bulk_push_server::receive () } else { - BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error receiving block type %1%") % ec.message ()); + if (this_l->connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (this_l->connection->node->log) << boost::str (boost::format ("Error receiving block type: %1%") % ec.message ()); + } } }); } @@ -2096,7 +2109,10 @@ void rai::bulk_push_server::received_type () } default: { - BOOST_LOG (connection->node->log) << "Unknown type received as block type"; + if (connection->node->config.logging.network_packet_logging ()) + { + BOOST_LOG (connection->node->log) << "Unknown type received as block type"; + } break; } } @@ -2115,7 +2131,10 @@ void rai::bulk_push_server::received_block (boost::system::error_code const & ec } else { - BOOST_LOG (connection->node->log) << "Error deserializing block received from pull request"; + if (connection->node->config.logging.bulk_pull_logging ()) + { + BOOST_LOG (connection->node->log) << "Error deserializing block received from pull request"; + } } } } @@ -2197,7 +2216,7 @@ void rai::frontier_req_server::no_block_sent (boost::system::error_code const & { if (connection->node->config.logging.network_logging ()) { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Error sending frontier finish %1%") % ec.message ()); + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Error sending frontier finish: %1%") % ec.message ()); } } } @@ -2212,7 +2231,7 @@ void rai::frontier_req_server::sent_action (boost::system::error_code const & ec { if (connection->node->config.logging.network_logging ()) { - BOOST_LOG (connection->node->log) << boost::str (boost::format ("Error sending frontier pair %1%") % ec.message ()); + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Error sending frontier pair: %1%") % ec.message ()); } } } diff --git a/rai/node/bootstrap.hpp b/rai/node/bootstrap.hpp index 99a58f7f..99adb431 100644 --- a/rai/node/bootstrap.hpp +++ b/rai/node/bootstrap.hpp @@ -15,6 +15,7 @@ namespace rai { class bootstrap_attempt; +class bootstrap_client; class node; enum class sync_result { @@ -22,6 +23,17 @@ enum class sync_result error, fork }; +class socket_timeout +{ +public: + socket_timeout (rai::bootstrap_client &); + void start (std::chrono::steady_clock::time_point); + void stop (); + +private: + std::atomic ticket; + rai::bootstrap_client & client; +}; /** * The length of every message header, parsed by rai::message::read_header () @@ -89,9 +101,9 @@ public: void add_pull (rai::pull_info const &); bool still_pulling (); void process_fork (MDB_txn *, std::shared_ptr); - void try_resolve_fork (MDB_txn *, std::shared_ptr, bool); - void resolve_forks (); unsigned target_connections (size_t pulls_remaining); + bool should_log (); + std::chrono::steady_clock::time_point next_log; std::deque> clients; std::weak_ptr connection_frontier_request; std::weak_ptr frontiers; @@ -103,7 +115,6 @@ public: std::shared_ptr node; std::atomic account_count; std::atomic total_blocks; - std::unordered_map> unresolved_forks; bool stopped; std::mutex mutex; std::condition_variable condition; @@ -127,13 +138,12 @@ public: rai::account landing; rai::account faucet; std::chrono::steady_clock::time_point start_time; - std::chrono::steady_clock::time_point next_report; std::promise promise; }; class bulk_pull_client : public std::enable_shared_from_this { public: - bulk_pull_client (std::shared_ptr, rai::pull_info const &, size_t); + bulk_pull_client (std::shared_ptr, rai::pull_info const &); ~bulk_pull_client (); void request (); void receive_block (); @@ -143,7 +153,6 @@ public: std::shared_ptr connection; rai::block_hash expected; rai::pull_info pull; - size_t size; }; class bootstrap_client : public std::enable_shared_from_this { @@ -160,9 +169,9 @@ public: std::shared_ptr node; std::shared_ptr attempt; boost::asio::ip::tcp::socket socket; + rai::socket_timeout timeout; std::array receive_buffer; rai::tcp_endpoint endpoint; - boost::asio::deadline_timer timeout; std::chrono::steady_clock::time_point start_time; std::atomic block_count; std::atomic pending_stop; @@ -192,13 +201,14 @@ public: void notify_listeners (bool); void add_observer (std::function const &); bool in_progress (); + std::shared_ptr current_attempt (); void process_fork (MDB_txn *, std::shared_ptr); void stop (); + +private: rai::node & node; std::shared_ptr attempt; bool stopped; - -private: std::mutex mutex; std::condition_variable condition; std::vector> observers; diff --git a/rai/node/common.cpp b/rai/node/common.cpp index d68a5df8..0c062d55 100644 --- a/rai/node/common.cpp +++ b/rai/node/common.cpp @@ -10,9 +10,9 @@ size_t constexpr rai::message::bootstrap_server_position; std::bitset<16> constexpr rai::message::block_type_mask; rai::message::message (rai::message_type type_a) : -version_max (0x07), -version_using (0x07), -version_min (0x01), +version_max (rai::protocol_version), +version_using (rai::protocol_version), +version_min (rai::protocol_version_min), type (type_a) { } diff --git a/rai/node/node.cpp b/rai/node/node.cpp index a9ff8ece..f66bf65d 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -91,7 +91,7 @@ void rai::network::send_keepalive (rai::endpoint const & endpoint_a) { if (ec && node_l->config.logging.network_keepalive_logging ()) { - BOOST_LOG (node_l->log) << boost::str (boost::format ("Error sending keepalive to %1% %2%") % endpoint_a % ec.message ()); + BOOST_LOG (node_l->log) << boost::str (boost::format ("Error sending keepalive to %1%: %2%") % endpoint_a % ec.message ()); } } }); @@ -115,7 +115,7 @@ void rai::node::keepalive (std::string const & address_a, uint16_t port_a) } else { - BOOST_LOG (node_l->log) << boost::str (boost::format ("Error resolving address: %1%:%2%, %3%") % address_a % port_a % ec.message ()); + BOOST_LOG (node_l->log) << boost::str (boost::format ("Error resolving address: %1%:%2%: %3%") % address_a % port_a % ec.message ()); } }); } @@ -133,28 +133,12 @@ void rai::network::republish (rai::block_hash const & hash_a, std::shared_ptrconfig.logging.network_logging ()) { - BOOST_LOG (node_l->log) << boost::str (boost::format ("Error sending publish: %1% to %2%") % ec.message () % endpoint_a); + BOOST_LOG (node_l->log) << boost::str (boost::format ("Error sending publish to %1%: %2%") % endpoint_a % ec.message ()); } } }); } -void rai::network::rebroadcast_reps (std::shared_ptr block_a) -{ - auto hash (block_a->hash ()); - rai::publish message (block_a); - std::shared_ptr> bytes (new std::vector); - { - rai::vectorstream stream (*bytes); - message.serialize (stream); - } - auto representatives (node.peers.representatives (2 * node.peers.size_sqrt ())); - for (auto i : representatives) - { - republish (hash, bytes, i.endpoint); - } -} - template bool confirm_block (MDB_txn * transaction_a, rai::node & node_a, T & list_a, std::shared_ptr block_a) { @@ -244,14 +228,32 @@ void rai::network::republish_vote (std::shared_ptr vote_a) void rai::network::broadcast_confirm_req (std::shared_ptr block_a) { - auto list (node.peers.representatives (std::numeric_limits::max ())); - for (auto i (list.begin ()), j (list.end ()); i != j; ++i) - { - node.network.send_confirm_req (i->endpoint, block_a); - } + auto list (std::make_shared> (node.peers.representatives (std::numeric_limits::max ()))); + broadcast_confirm_req_base (block_a, list, 0); +} + +void rai::network::broadcast_confirm_req_base (std::shared_ptr block_a, std::shared_ptr> endpoints_a, unsigned delay_a) +{ if (node.config.logging.network_logging ()) { - BOOST_LOG (node.log) << boost::str (boost::format ("Broadcasted confirm req for block %1% to %2% representatives") % block_a->hash ().to_string () % list.size ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Broadcasting confirm req for block %1% to %2% representatives") % block_a->hash ().to_string () % endpoints_a->size ()); + } + auto count (0); + while (!endpoints_a->empty () && count < 10) + { + send_confirm_req (endpoints_a->back ().endpoint, block_a); + endpoints_a->pop_back (); + count++; + } + if (!endpoints_a->empty ()) + { + std::weak_ptr node_w (node.shared ()); + node.alarm.add (std::chrono::steady_clock::now () + std::chrono::milliseconds (delay_a), [node_w, block_a, endpoints_a, delay_a]() { + if (auto node_l = node_w.lock ()) + { + node_l->network.broadcast_confirm_req_base (block_a, endpoints_a, delay_a + 50); + } + }); } } @@ -352,9 +354,10 @@ public: node.peers.insert (sender, message_a.version_using); node.process_active (message_a.block); rai::transaction transaction_a (node.store.environment, nullptr, false); - if (node.store.block_exists (transaction_a, message_a.block->hash ())) + auto successor (node.ledger.successor (transaction_a, message_a.block->root ())); + if (successor != nullptr) { - confirm_block (transaction_a, node, sender, message_a.block); + confirm_block (transaction_a, node, sender, std::move (successor)); } } void confirm_ack (rai::confirm_ack const & message_a) override @@ -791,7 +794,8 @@ peering_port (peering_port_a), logging (logging_a), bootstrap_fraction_numerator (1), receive_minimum (rai::xrb_ratio), -inactive_supply (0), +online_weight_minimum (rai::genesis_amount / 4), +online_weight_quorom (50), password_fanout (1024), io_threads (std::max (4, std::thread::hardware_concurrency ())), work_threads (std::max (4, std::thread::hardware_concurrency ())), @@ -835,7 +839,7 @@ state_block_generate_canary (0) void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) const { - tree_a.put ("version", "10"); + tree_a.put ("version", "11"); tree_a.put ("peering_port", std::to_string (peering_port)); tree_a.put ("bootstrap_fraction_numerator", std::to_string (bootstrap_fraction_numerator)); tree_a.put ("receive_minimum", receive_minimum.to_string_dec ()); @@ -866,7 +870,8 @@ void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) con preconfigured_representatives_l.push_back (std::make_pair ("", entry)); } tree_a.add_child ("preconfigured_representatives", preconfigured_representatives_l); - tree_a.put ("inactive_supply", inactive_supply.to_string_dec ()); + tree_a.put ("online_weight_minimum", online_weight_minimum.to_string_dec ()); + tree_a.put ("online_weight_quorom", std::to_string (online_weight_quorom)); tree_a.put ("password_fanout", std::to_string (password_fanout)); tree_a.put ("io_threads", std::to_string (io_threads)); tree_a.put ("work_threads", std::to_string (work_threads)); @@ -959,6 +964,13 @@ bool rai::node_config::upgrade_json (unsigned version, boost::property_tree::ptr tree_a.put ("version", "10"); result = true; case 10: + tree_a.put ("online_weight_minimum", online_weight_minimum.to_string_dec ()); + tree_a.put ("online_weight_quorom", std::to_string (online_weight_quorom)); + tree_a.erase ("inactive_supply"); + tree_a.erase ("version"); + tree_a.put ("version", "11"); + result = true; + case 11: break; default: throw std::runtime_error ("Unknown node_config version"); @@ -1020,7 +1032,8 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree { result = true; } - auto inactive_supply_l (tree_a.get ("inactive_supply")); + auto online_weight_minimum_l (tree_a.get ("online_weight_minimum")); + auto online_weight_quorom_l (tree_a.get ("online_weight_quorom")); auto password_fanout_l (tree_a.get ("password_fanout")); auto io_threads_l (tree_a.get ("io_threads")); auto work_threads_l (tree_a.get ("work_threads")); @@ -1044,14 +1057,15 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree bootstrap_connections = std::stoul (bootstrap_connections_l); bootstrap_connections_max = std::stoul (bootstrap_connections_max_l); lmdb_max_dbs = std::stoi (lmdb_max_dbs_l); + online_weight_quorom = std::stoul (online_weight_quorom_l); result |= peering_port > std::numeric_limits::max (); result |= logging.deserialize_json (upgraded_a, logging_l); result |= receive_minimum.decode_dec (receive_minimum_l); - result |= inactive_supply.decode_dec (inactive_supply_l); + result |= online_weight_minimum.decode_dec (online_weight_minimum_l); + result |= online_weight_quorom > 100; result |= password_fanout < 16; result |= password_fanout > 1024 * 1024; result |= io_threads == 0; - result |= work_threads == 0; result |= state_block_parse_canary.decode_hex (state_block_parse_canary_l); result |= state_block_generate_canary.decode_hex (state_block_generate_canary_l); } @@ -1146,21 +1160,11 @@ bool rai::rep_crawler::exists (rai::block_hash const & hash_a) return active.count (hash_a) != 0; } -rai::block_processor_item::block_processor_item (std::shared_ptr block_a) : -block_processor_item (block_a, false) -{ -} - -rai::block_processor_item::block_processor_item (std::shared_ptr block_a, bool force_a) : -block (block_a), -force (force_a) -{ -} - rai::block_processor::block_processor (rai::node & node_a) : stopped (false), -idle (true), -node (node_a) +active (false), +node (node_a), +next_log (std::chrono::steady_clock::now ()) { } @@ -1179,16 +1183,23 @@ void rai::block_processor::stop () void rai::block_processor::flush () { std::unique_lock lock (mutex); - while (!stopped && (!blocks.empty () || !idle)) + while (!stopped && (!blocks.empty () || active)) { condition.wait (lock); } } -void rai::block_processor::add (rai::block_processor_item const & item_a) +void rai::block_processor::add (std::shared_ptr block_a) { std::lock_guard lock (mutex); - blocks.push_back (item_a); + blocks.push_front (block_a); + condition.notify_all (); +} + +void rai::block_processor::force (std::shared_ptr block_a) +{ + std::lock_guard lock (mutex); + forced.push_front (block_a); condition.notify_all (); } @@ -1197,93 +1208,106 @@ void rai::block_processor::process_blocks () std::unique_lock lock (mutex); while (!stopped) { - if (!blocks.empty ()) + if (have_blocks ()) { - std::deque blocks_processing; - std::swap (blocks, blocks_processing); + active = true; lock.unlock (); - process_receive_many (blocks_processing); - // Let other threads get an opportunity to transaction lock - std::this_thread::yield (); + process_receive_many (lock); lock.lock (); + active = false; } else { - idle = true; condition.notify_all (); condition.wait (lock); - idle = false; } } } -void rai::block_processor::process_receive_many (rai::block_processor_item const & item_a) +bool rai::block_processor::should_log () { - std::deque blocks_processing; - blocks_processing.push_back (item_a); - process_receive_many (blocks_processing); -} - -void rai::block_processor::process_receive_many (std::deque & blocks_processing) -{ - while (!blocks_processing.empty ()) + auto result (false); + auto now (std::chrono::steady_clock::now ()); + if (next_log < now) { - std::deque, rai::process_return>> progress; + next_log = now + std::chrono::seconds (15); + result = true; + } + return result; +} + +bool rai::block_processor::have_blocks () +{ + assert (!mutex.try_lock ()); + return !blocks.empty () || !forced.empty (); +} + +void rai::block_processor::process_receive_many (std::unique_lock & lock_a) +{ + { + rai::transaction transaction (node.store.environment, nullptr, true); + auto cutoff (std::chrono::steady_clock::now () + rai::transaction_timeout); + lock_a.lock (); + while (have_blocks () && std::chrono::steady_clock::now () < cutoff) { - rai::transaction transaction (node.store.environment, nullptr, true); - auto cutoff (std::chrono::steady_clock::now () + rai::transaction_timeout); - while (!blocks_processing.empty () && std::chrono::steady_clock::now () < cutoff) + if (blocks.size () > 64 && should_log ()) { - auto item (blocks_processing.front ()); - blocks_processing.pop_front (); - auto hash (item.block->hash ()); - if (item.force) + BOOST_LOG (node.log) << boost::str (boost::format ("%1% blocks in processing queue") % blocks.size ()); + } + std::shared_ptr block; + bool force (false); + if (forced.empty ()) + { + block = blocks.front (); + blocks.pop_front (); + } + else + { + block = forced.front (); + forced.pop_front (); + force = true; + } + lock_a.unlock (); + auto hash (block->hash ()); + if (force) + { + auto successor (node.ledger.successor (transaction, block->root ())); + if (successor != nullptr && successor->hash () != hash) { - auto successor (node.ledger.successor (transaction, item.block->root ())); - if (successor != nullptr && successor->hash () != hash) - { - // Replace our block with the winner and roll back any dependent blocks - BOOST_LOG (node.log) << boost::str (boost::format ("Rolling back %1% and replacing with %2%") % successor->hash ().to_string () % hash.to_string ()); - node.ledger.rollback (transaction, successor->hash ()); - } - } - auto process_result (process_receive_one (transaction, item.block)); - switch (process_result.code) - { - case rai::process_result::progress: - { - progress.push_back (std::make_pair (item.block, process_result)); - } - case rai::process_result::old: - { - auto cached (node.store.unchecked_get (transaction, hash)); - for (auto i (cached.begin ()), n (cached.end ()); i != n; ++i) - { - node.store.unchecked_del (transaction, hash, **i); - blocks_processing.push_front (rai::block_processor_item (*i)); - } - std::lock_guard lock (node.gap_cache.mutex); - node.gap_cache.blocks.get<1> ().erase (hash); - break; - } - default: - break; + // Replace our block with the winner and roll back any dependent blocks + BOOST_LOG (node.log) << boost::str (boost::format ("Rolling back %1% and replacing with %2%") % successor->hash ().to_string () % hash.to_string ()); + node.ledger.rollback (transaction, successor->hash ()); } } - } - for (auto & i : progress) - { - node.observers.blocks (i.first, i.second); - if (i.second.amount > 0) + auto process_result (process_receive_one (transaction, block)); + switch (process_result.code) { - node.observers.account_balance (i.second.account, false); - if (!i.second.pending_account.is_zero ()) + case rai::process_result::progress: { - node.observers.account_balance (i.second.pending_account, true); + if (node.block_arrival.recent (hash)) + { + node.active.start (transaction, block); + } } + case rai::process_result::old: + { + auto cached (node.store.unchecked_get (transaction, hash)); + for (auto i (cached.begin ()), n (cached.end ()); i != n; ++i) + { + node.store.unchecked_del (transaction, hash, **i); + add (*i); + } + std::lock_guard lock (node.gap_cache.mutex); + node.gap_cache.blocks.get<1> ().erase (hash); + break; + } + default: + break; } + lock_a.lock (); } } + lock_a.unlock (); } rai::process_return rai::block_processor::process_receive_one (MDB_txn * transaction_a, std::shared_ptr block_a) @@ -1298,7 +1322,7 @@ rai::process_return rai::block_processor::process_receive_one (MDB_txn * transac { std::string block; block_a->serialize_json (block); - BOOST_LOG (node.log) << boost::str (boost::format ("Processing block %1% %2%") % block_a->hash ().to_string () % block); + BOOST_LOG (node.log) << boost::str (boost::format ("Processing block %1%: %2%") % block_a->hash ().to_string () % block); } break; } @@ -1430,7 +1454,7 @@ alarm (alarm_a), work (work_a), store (init_a.block_store_init, application_path_a / "data.ldb", config_a.lmdb_max_dbs), gap_cache (*this), -ledger (store, config_a.inactive_supply.number (), config.state_block_parse_canary, config.state_block_generate_canary), +ledger (store, config.state_block_parse_canary, config.state_block_generate_canary), active (*this), network (*this, config.peering_port), bootstrap_initiator (*this), @@ -1454,30 +1478,23 @@ online_reps (*this) peers.disconnect_observer = [this]() { observers.disconnect (); }; - observers.blocks.add ([this](std::shared_ptr block_a, rai::process_return const & result_a) { - if (this->block_arrival.recent (block_a->hash ())) - { - rai::transaction transaction (store.environment, nullptr, false); - active.start (transaction, block_a); - } - }); - observers.blocks.add ([this](std::shared_ptr block_a, rai::process_return const & result_a) { + observers.blocks.add ([this](std::shared_ptr block_a, rai::account const & account_a, rai::amount const & amount_a, bool is_state_send_a) { if (this->block_arrival.recent (block_a->hash ())) { auto node_l (shared_from_this ()); - background ([node_l, block_a, result_a]() { + background ([node_l, block_a, account_a, amount_a, is_state_send_a]() { if (!node_l->config.callback_address.empty ()) { boost::property_tree::ptree event; - event.add ("account", result_a.account.to_account ()); + event.add ("account", account_a.to_account ()); event.add ("hash", block_a->hash ().to_string ()); std::string block_text; block_a->serialize_json (block_text); event.add ("block", block_text); - event.add ("amount", result_a.amount.to_string_dec ()); - if (result_a.state_is_send) + event.add ("amount", amount_a.to_string_dec ()); + if (is_state_send_a) { - event.add ("is_send", *result_a.state_is_send); + event.add ("is_send", is_state_send_a); } std::stringstream ostream; boost::property_tree::write_json (ostream, event); @@ -1529,7 +1546,7 @@ online_reps (*this) { if (node_l->config.logging.callback_logging ()) { - BOOST_LOG (node_l->log) << boost::str (boost::format ("Unable complete callback: %1%:%2% %3%") % address % port % ec.message ()); + BOOST_LOG (node_l->log) << boost::str (boost::format ("Unable complete callback: %1%:%2%: %3%") % address % port % ec.message ()); } }; }); @@ -1538,7 +1555,7 @@ online_reps (*this) { if (node_l->config.logging.callback_logging ()) { - BOOST_LOG (node_l->log) << boost::str (boost::format ("Unable to send callback: %1%:%2% %3%") % address % port % ec.message ()); + BOOST_LOG (node_l->log) << boost::str (boost::format ("Unable to send callback: %1%:%2%: %3%") % address % port % ec.message ()); } } }); @@ -1547,7 +1564,7 @@ online_reps (*this) { if (node_l->config.logging.callback_logging ()) { - BOOST_LOG (node_l->log) << boost::str (boost::format ("Unable to connect to callback address: %1%:%2%, %3%") % address % port % ec.message ()); + BOOST_LOG (node_l->log) << boost::str (boost::format ("Unable to connect to callback address: %1%:%2%: %3%") % address % port % ec.message ()); } } }); @@ -1557,7 +1574,7 @@ online_reps (*this) { if (node_l->config.logging.callback_logging ()) { - BOOST_LOG (node_l->log) << boost::str (boost::format ("Error resolving callback: %1%:%2%, %3%") % address % port % ec.message ()); + BOOST_LOG (node_l->log) << boost::str (boost::format ("Error resolving callback: %1%:%2%: %3%") % address % port % ec.message ()); } } }); @@ -1576,20 +1593,29 @@ online_reps (*this) this->online_reps.vote (vote_a); }); observers.vote.add ([this](std::shared_ptr vote_a, rai::endpoint const & endpoint_a) { - if (this->rep_crawler.exists (vote_a->block->hash ())) + rai::uint128_t rep_weight; + rai::uint128_t min_rep_weight; { - auto weight_l (weight (vote_a->account)); - // We see a valid non-replay vote for a block we requested, this node is probably a representative - if (peers.rep_response (endpoint_a, weight_l)) + rai::transaction transaction (store.environment, nullptr, false); + rep_weight = ledger.weight (transaction, vote_a->account); + min_rep_weight = ledger.supply (transaction) / 1000; + } + if (rep_weight > min_rep_weight) + { + if (this->rep_crawler.exists (vote_a->block->hash ())) { - BOOST_LOG (log) << boost::str (boost::format ("Found a representative at %1%") % endpoint_a); - // Rebroadcasting all active votes to new representative - auto blocks (active.list_blocks ()); - for (auto i (blocks.begin ()), n (blocks.end ()); i != n; ++i) + // We see a valid non-replay vote for a block we requested, this node is probably a representative + if (peers.rep_response (endpoint_a, vote_a->account, rep_weight)) { - if (*i != nullptr) + BOOST_LOG (log) << boost::str (boost::format ("Found a representative at %1%") % endpoint_a); + // Rebroadcasting all active votes to new representative + auto blocks (active.list_blocks ()); + for (auto i (blocks.begin ()), n (blocks.end ()); i != n; ++i) { - this->network.send_confirm_req (endpoint_a, *i); + if (*i != nullptr) + { + this->network.send_confirm_req (endpoint_a, *i); + } } } } @@ -1866,7 +1892,7 @@ bool rai::parse_address_port (std::string const & string, boost::asio::ip::addre { boost::system::error_code ec; auto address (boost::asio::ip::address_v6::from_string (string.substr (0, port_position), ec)); - if (ec == 0) + if (!ec) { address_a = address; port_a = port; @@ -2027,7 +2053,7 @@ void rai::node::ongoing_rep_crawl () if (network.on) { std::weak_ptr node_w (shared_from_this ()); - alarm.add (now + period, [node_w]() { + alarm.add (now + std::chrono::seconds (4), [node_w]() { if (auto node_l = node_w.lock ()) { node_l->ongoing_rep_crawl (); @@ -2124,10 +2150,11 @@ public: class distributed_work : public std::enable_shared_from_this { public: - distributed_work (std::shared_ptr const & node_a, rai::block_hash const & root_a, std::function callback_a) : + distributed_work (std::shared_ptr const & node_a, rai::block_hash const & root_a, std::function callback_a, unsigned int backoff_a = 1) : callback (callback_a), node (node_a), - root (root_a) + root (root_a), + backoff (backoff_a) { completed.clear (); for (auto & i : node_a->config.work_peers) @@ -2259,19 +2286,19 @@ public: } else { - BOOST_LOG (node->log) << boost::str (boost::format ("Incorrect work response from %1% for root %2% value %3%") % address % root.to_string () % work_text); + BOOST_LOG (node->log) << boost::str (boost::format ("Incorrect work response from %1% for root %2%: %3%") % address % root.to_string () % work_text); handle_failure (last); } } else { - BOOST_LOG (node->log) << boost::str (boost::format ("Work response from %1% wasn't a number %2%") % address % work_text); + BOOST_LOG (node->log) << boost::str (boost::format ("Work response from %1% wasn't a number: %2%") % address % work_text); handle_failure (last); } } catch (...) { - BOOST_LOG (node->log) << boost::str (boost::format ("Work response from %1% wasn't parsable %2%") % address % body_a); + BOOST_LOG (node->log) << boost::str (boost::format ("Work response from %1% wasn't parsable: %2%") % address % body_a); handle_failure (last); } } @@ -2293,10 +2320,32 @@ public: { if (!completed.test_and_set ()) { - auto callback_l (callback); - node->work.generate (root, [callback_l](boost::optional const & work_a) { - callback_l (work_a.value ()); - }); + if (node->config.work_threads != 0 || node->work.opencl) + { + auto callback_l (callback); + node->work.generate (root, [callback_l](boost::optional const & work_a) { + callback_l (work_a.value ()); + }); + } + else + { + if (backoff == 1 && node->config.logging.work_generation_time ()) + { + BOOST_LOG (node->log) << "Work peer(s) failed to generate work for root " << root.to_string () << ", retrying..."; + } + auto now (std::chrono::steady_clock::now ()); + auto root_l (root); + auto callback_l (callback); + std::weak_ptr node_w (node); + auto next_backoff (std::min (backoff * 2, (unsigned int)60 * 5)); + node->alarm.add (now + std::chrono::seconds (backoff), [node_w, root_l, callback_l, next_backoff] { + if (auto node_l = node_w.lock ()) + { + auto work_generation (std::make_shared (node_l, root_l, callback_l, next_backoff)); + work_generation->start (); + } + }); + } } } } @@ -2307,6 +2356,7 @@ public: return outstanding.empty (); } std::function callback; + unsigned int backoff; // in seconds std::shared_ptr node; rai::block_hash root; std::mutex mutex; @@ -2339,14 +2389,23 @@ void rai::node::add_initial_peers () { } +void rai::node::block_confirm (std::shared_ptr block_a) +{ + rai::transaction transaction (store.environment, nullptr, false); + active.start (transaction, block_a); + network.broadcast_confirm_req (block_a); +} + namespace { class confirmed_visitor : public rai::block_visitor { public: - confirmed_visitor (rai::node & node_a, std::shared_ptr block_a) : + confirmed_visitor (MDB_txn * transaction_a, rai::node & node_a, std::shared_ptr block_a, rai::block_hash const & hash_a) : + transaction (transaction_a), node (node_a), - block (block_a) + block (block_a), + hash (hash_a) { } virtual ~confirmed_visitor () = default; @@ -2355,13 +2414,12 @@ public: for (auto i (node.wallets.items.begin ()), n (node.wallets.items.end ()); i != n; ++i) { auto wallet (i->second); - if (wallet->exists (account_a)) + if (wallet->store.exists (transaction, account_a)) { rai::account representative; rai::pending_info pending; - rai::transaction transaction (node.store.environment, nullptr, false); representative = wallet->store.representative (transaction); - auto error (node.store.pending_get (transaction, rai::pending_key (account_a, block->hash ()), pending)); + auto error (node.store.pending_get (transaction, rai::pending_key (account_a, hash), pending)); if (!error) { auto node_l (node.shared ()); @@ -2370,9 +2428,13 @@ public: } else { - if (node.config.logging.ledger_duplicate_logging ()) + if (node.store.block_exists (transaction, hash)) { - BOOST_LOG (node.log) << boost::str (boost::format ("Block confirmed before timeout %1%") % block->hash ().to_string ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Block %1% has already been received") % block->hash ().to_string ()); + } + else + { + assert (false && "Confirmed block is missing"); } } } @@ -2395,15 +2457,61 @@ public: void change_block (rai::change_block const &) override { } + MDB_txn * transaction; rai::node & node; std::shared_ptr block; + rai::block_hash const & hash; }; } -void rai::node::process_confirmed (std::shared_ptr confirmed_a) +void rai::node::process_confirmed (std::shared_ptr block_a) { - confirmed_visitor visitor (*this, confirmed_a); - confirmed_a->visit (visitor); + rai::transaction transaction (store.environment, nullptr, false); + auto hash (block_a->hash ()); + if (store.block_exists (transaction, hash)) + { + confirmed_visitor visitor (transaction, *this, block_a, hash); + block_a->visit (visitor); + auto account (ledger.account (transaction, hash)); + auto amount (ledger.amount (transaction, hash)); + bool is_state_send (false); + rai::account pending_account (0); + if (auto state = dynamic_cast (block_a.get ())) + { + rai::transaction transaction (store.environment, nullptr, false); + is_state_send = ledger.is_send (transaction, *state); + pending_account = state->hashables.link; + } + if (auto send = dynamic_cast (block_a.get ())) + { + pending_account = send->hashables.destination; + } + observers.blocks (block_a, account, amount, is_state_send); + if (amount > 0) + { + observers.account_balance (account, false); + if (!pending_account.is_zero ()) + { + observers.account_balance (pending_account, true); + } + } + } + else + { + std::cerr << boost::str (boost::format ("Confirmed block %1% not in ledger\n") % hash.to_string ()); + alarm.add (std::chrono::steady_clock::now () + std::chrono::seconds (5), [hash, this_l = shared()] () + { + rai::transaction transaction (this_l->store.environment, nullptr, false); + if (this_l->store.block_exists (transaction, hash)) + { + std::cerr << boost::str (boost::format ("Block %1% appeared in ledger\n") % hash.to_string ()); + } + else + { + std::cerr << boost::str (boost::format ("Block %1% still not in ledger\n") % hash.to_string ()); + } + }); + } } void rai::node::process_message (rai::message & message_a, rai::endpoint const & sender_a) @@ -2605,10 +2713,10 @@ std::vector rai::peer_container::purge_list (std::chrono: std::vector rai::peer_container::rep_crawl () { std::vector result; - result.reserve (8); + result.reserve (10); std::lock_guard lock (mutex); auto count (0); - for (auto i (peers.get<5> ().begin ()), n (peers.get<5> ().end ()); i != n && count < 8; ++i, ++count) + for (auto i (peers.get<5> ().begin ()), n (peers.get<5> ().end ()); i != n && count < 10; ++i, ++count) { result.push_back (i->endpoint); }; @@ -2650,19 +2758,20 @@ bool rai::peer_container::not_a_peer (rai::endpoint const & endpoint_a) return result; } -bool rai::peer_container::rep_response (rai::endpoint const & endpoint_a, rai::amount const & weight_a) +bool rai::peer_container::rep_response (rai::endpoint const & endpoint_a, rai::account const & rep_account_a, rai::amount const & weight_a) { auto updated (false); std::lock_guard lock (mutex); auto existing (peers.find (endpoint_a)); if (existing != peers.end ()) { - peers.modify (existing, [weight_a, &updated](rai::peer_information & info) { + peers.modify (existing, [weight_a, &updated, rep_account_a](rai::peer_information & info) { info.last_rep_response = std::chrono::steady_clock::now (); if (info.rep_weight < weight_a) { updated = true; info.rep_weight = weight_a; + info.probable_rep_account = rep_account_a; } }); } @@ -2703,19 +2812,22 @@ bool rai::peer_container::insert (rai::endpoint const & endpoint_a, unsigned ver auto result (not_a_peer (endpoint_a)); if (!result) { - std::lock_guard lock (mutex); - auto existing (peers.find (endpoint_a)); - if (existing != peers.end ()) + if (version_a >= rai::protocol_version_min) { - peers.modify (existing, [](rai::peer_information & info) { - info.last_contact = std::chrono::steady_clock::now (); - }); - result = true; - } - else - { - peers.insert (rai::peer_information (endpoint_a, version_a)); - unknown = true; + std::lock_guard lock (mutex); + auto existing (peers.find (endpoint_a)); + if (existing != peers.end ()) + { + peers.modify (existing, [](rai::peer_information & info) { + info.last_contact = std::chrono::steady_clock::now (); + }); + result = true; + } + else + { + peers.insert (rai::peer_information (endpoint_a, version_a)); + unknown = true; + } } } if (unknown && !result) @@ -2906,12 +3018,6 @@ rai::uint128_t rai::election::quorum_threshold (MDB_txn * transaction_a, rai::le return ledger_a.supply (transaction_a) / 2; } -rai::uint128_t rai::election::minimum_threshold (MDB_txn * transaction_a, rai::ledger & ledger_a) -{ - // Minimum number of votes needed to change our ledger, under which we're probably disconnected - return ledger_a.supply (transaction_a) / 16; -} - void rai::election::confirm_once (MDB_txn * transaction_a) { if (!confirmed.exchange (true)) @@ -2920,15 +3026,31 @@ void rai::election::confirm_once (MDB_txn * transaction_a) assert (tally_l.size () > 0); auto winner (tally_l.begin ()); auto block_l (winner->second); - auto exceeded_min_threshold = winner->first > minimum_threshold (transaction_a, node.ledger); + rai::uint128_t total (0); + for (auto & i : tally_l) + { + total += i.first; + } + auto quorom_minimum ((total / 100) * node.config.online_weight_quorom); + auto exceeded_min_threshold = total > node.config.online_weight_minimum.number () && winner->first > quorom_minimum; + if (node.config.logging.vote_logging () || !votes.uncontested ()) + { + BOOST_LOG (node.log) << boost::str (boost::format ("Vote tally for root %1%") % status.winner->root ().to_string ()); + for (auto i (tally_l.begin ()), n (tally_l.end ()); i != n; ++i) + { + BOOST_LOG (node.log) << boost::str (boost::format ("Block %1% weight %2%") % i->second->hash ().to_string () % i->first.convert_to ()); + } + for (auto i (votes.rep_votes.begin ()), n (votes.rep_votes.end ()); i != n; ++i) + { + BOOST_LOG (node.log) << boost::str (boost::format ("%1% %2%") % i->first.to_account () % i->second->hash ().to_string ()); + } + } if (!(*block_l == *status.winner)) { if (exceeded_min_threshold) { auto node_l (node.shared ()); - node.background ([node_l, block_l]() { - node_l->block_processor.process_receive_many (rai::block_processor_item (block_l, true)); - }); + node_l->block_processor.force (block_l); status.winner = block_l; } else @@ -2940,7 +3062,7 @@ void rai::election::confirm_once (MDB_txn * transaction_a) auto winner_l (status.winner); auto node_l (node.shared ()); auto confirmation_action_l (confirmation_action); - node.background ([winner_l, confirmation_action_l, node_l, exceeded_min_threshold]() { + node.background ([node_l, winner_l, confirmation_action_l, exceeded_min_threshold]() { node_l->process_confirmed (winner_l); confirmation_action_l (winner_l, exceeded_min_threshold); }); @@ -2966,14 +3088,6 @@ void rai::election::confirm_if_quorum (MDB_txn * transaction_a) void rai::election::confirm_cutoff (MDB_txn * transaction_a) { - if (node.config.logging.vote_logging ()) - { - BOOST_LOG (node.log) << boost::str (boost::format ("Vote tally weight %2% for root %1%") % votes.id.to_string () % status.winner->root ().to_string ()); - for (auto i (votes.rep_votes.begin ()), n (votes.rep_votes.end ()); i != n; ++i) - { - BOOST_LOG (node.log) << boost::str (boost::format ("%1% %2%") % i->first.to_account () % i->second->hash ().to_string ()); - } - } confirm_once (transaction_a); } @@ -3070,6 +3184,36 @@ void rai::active_transactions::announce_votes () { node.bootstrap_initiator.bootstrap (); } + else if (i->confirm_req_options.second != nullptr) + { + auto reps (std::make_shared> (node.peers.representatives (std::numeric_limits::max ()))); + + for (auto j (reps->begin ()), m (reps->end ()); j != m;) + { + auto & rep_votes (i->election->votes.rep_votes); + auto rep_acct (j->probable_rep_account); + if (rep_votes.find (rep_acct) != rep_votes.end ()) + { + std::swap (*j, reps->back ()); + reps->pop_back (); + m = reps->end (); + } + else + { + ++j; + if (node.config.logging.vote_logging ()) + { + BOOST_LOG (node.log) << "Representative did not respond to confirm_req, retrying: " << rep_acct.to_account (); + } + } + } + if (!reps->empty ()) + { + // broadcast_confirm_req_base modifies reps, so we clone it once to avoid aliasing + node.network.broadcast_confirm_req_base (i->confirm_req_options.first, std::make_shared> (*reps), 0); + node.network.broadcast_confirm_req_base (i->confirm_req_options.second, reps, 0); + } + } } } // Mark remainder as 0 announcements sent @@ -3089,8 +3233,13 @@ void rai::active_transactions::announce_votes () roots.erase (*i); } auto now (std::chrono::steady_clock::now ()); - auto node_l (node.shared ()); - node.alarm.add (now + std::chrono::milliseconds (announce_interval_ms), [node_l]() { node_l->active.announce_votes (); }); + std::weak_ptr node_w (node.shared ()); + node.alarm.add (now + std::chrono::milliseconds (announce_interval_ms), [node_w]() { + if (auto node_l = node_w.lock ()) + { + node_l->active.announce_votes (); + } + }); } void rai::active_transactions::stop () @@ -3101,13 +3250,20 @@ void rai::active_transactions::stop () bool rai::active_transactions::start (MDB_txn * transaction_a, std::shared_ptr block_a, std::function, bool)> const & confirmation_action_a) { + return start (transaction_a, std::make_pair (block_a, nullptr), confirmation_action_a); +} + +bool rai::active_transactions::start (MDB_txn * transaction_a, std::pair, std::shared_ptr> blocks_a, std::function, bool)> const & confirmation_action_a) +{ + assert (blocks_a.first != nullptr); std::lock_guard lock (mutex); - auto root (block_a->root ()); + auto primary_block (blocks_a.first); + auto root (primary_block->root ()); auto existing (roots.find (root)); if (existing == roots.end ()) { - auto election (std::make_shared (transaction_a, node, block_a, confirmation_action_a)); - roots.insert (rai::conflict_info{ root, election, 0 }); + auto election (std::make_shared (transaction_a, node, primary_block, confirmation_action_a)); + roots.insert (rai::conflict_info{ root, election, 0, blocks_a }); } return existing != roots.end (); } @@ -3908,7 +4064,7 @@ void rai::port_mapping::refresh_devices () } if (check_count % 15 == 0) { - BOOST_LOG (node.log) << boost::str (boost::format ("UPnP local address: %3%, discovery: %1%, IGD search: %2%") % discover_error % igd_error % local_address.data ()); + BOOST_LOG (node.log) << boost::str (boost::format ("UPnP local address: %1%, discovery: %2%, IGD search: %3%") % local_address.data () % discover_error % igd_error); for (auto i (devices); i != nullptr; i = i->pNext) { BOOST_LOG (node.log) << boost::str (boost::format ("UPnP device url: %1% st: %2% usn: %3%") % i->descURL % i->st % i->usn); @@ -3932,7 +4088,7 @@ void rai::port_mapping::refresh_mapping () auto add_port_mapping_error (UPNP_AddAnyPortMapping (urls.controlURL, data.first.servicetype, node_port.c_str (), node_port.c_str (), address.to_string ().c_str (), nullptr, protocol.name, nullptr, std::to_string (mapping_timeout).c_str (), actual_external_port.data ())); if (check_count % 15 == 0) { - BOOST_LOG (node.log) << boost::str (boost::format ("UPnP %1% port mapping response: %2%, actual external port %5%") % protocol.name % add_port_mapping_error % 0 % 0 % actual_external_port.data ()); + BOOST_LOG (node.log) << boost::str (boost::format ("UPnP %1% port mapping response: %2%, actual external port %3%") % protocol.name % add_port_mapping_error % actual_external_port.data ()); } if (add_port_mapping_error == UPNPCOMMAND_SUCCESS) { @@ -3984,7 +4140,7 @@ int rai::port_mapping::check_mapping () } if (check_count % 15 == 0) { - BOOST_LOG (node.log) << boost::str (boost::format ("UPnP %3% mapping verification response: %1%, external ip response: %6%, external ip: %4%, internal ip: %5%, remaining lease: %2%") % verify_port_mapping_error % remaining_mapping_duration.data () % protocol.name % external_address.data () % address.to_string () % external_ip_error); + BOOST_LOG (node.log) << boost::str (boost::format ("UPnP %1% mapping verification response: %2%, external ip response: %3%, external ip: %4%, internal ip: %5%, remaining lease: %6%") % protocol.name % verify_port_mapping_error % external_ip_error % external_address.data () % address.to_string () % remaining_mapping_duration.data ()); } } } diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 0caf37b8..344ee32d 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -61,7 +61,6 @@ public: // Confirmation method 2, settling time void confirm_cutoff (MDB_txn *); rai::uint128_t quorum_threshold (MDB_txn *, rai::ledger &); - rai::uint128_t minimum_threshold (MDB_txn *, rai::ledger &); rai::votes votes; rai::node & node; std::unordered_map> last_votes; @@ -75,6 +74,7 @@ public: std::shared_ptr election; // Number of announcements in a row for this fork unsigned announcements; + std::pair, std::shared_ptr> confirm_req_options; }; // Core class for determining consensus // Holds all active blocks i.e. recently added blocks that need confirmation @@ -85,6 +85,10 @@ public: // Start an election for a block // Call action with confirmed block, may be different than what we started with bool start (MDB_txn *, std::shared_ptr, std::function, bool)> const & = [](std::shared_ptr, bool) {}); + // Also supply alternatives to block, to confirm_req reps with if the boolean argument is true + // Should only be used for old elections + // The first block should be the one in the ledger + bool start (MDB_txn *, std::pair, std::shared_ptr>, std::function, bool)> const & = [](std::shared_ptr, bool) {}); // If this returns true, the vote is a replay // If this returns false, the vote may or may not be a replay bool vote (std::shared_ptr); @@ -166,6 +170,7 @@ public: std::chrono::steady_clock::time_point last_rep_request; std::chrono::steady_clock::time_point last_rep_response; rai::amount rep_weight; + rai::account probable_rep_account; unsigned network_version; }; class peer_attempt @@ -200,7 +205,7 @@ public: // Purge any peer where last_contact < time_point and return what was left std::vector purge_list (std::chrono::steady_clock::time_point const &); std::vector rep_crawl (); - bool rep_response (rai::endpoint const &, rai::amount const &); + bool rep_response (rai::endpoint const &, rai::account const &, rai::amount const &); void rep_request (rai::endpoint const &); // Should we reach out to this endpoint with a keepalive message bool reachout (rai::endpoint const &); @@ -339,7 +344,6 @@ public: void stop (); void receive_action (boost::system::error_code const &, size_t); void rpc_action (boost::system::error_code const &, size_t); - void rebroadcast_reps (std::shared_ptr); void republish_vote (std::shared_ptr); void republish_block (MDB_txn *, std::shared_ptr); void republish (rai::block_hash const &, std::shared_ptr>, rai::endpoint); @@ -348,6 +352,7 @@ public: void merge_peers (std::array const &); void send_keepalive (rai::endpoint const &); void broadcast_confirm_req (std::shared_ptr); + void broadcast_confirm_req_base (std::shared_ptr, std::shared_ptr>, unsigned); void send_confirm_req (rai::endpoint const &, std::shared_ptr); void send_buffer (uint8_t const *, size_t, rai::endpoint const &, std::function); rai::endpoint endpoint (); @@ -432,7 +437,8 @@ public: std::vector preconfigured_representatives; unsigned bootstrap_fraction_numerator; rai::amount receive_minimum; - rai::amount inactive_supply; + rai::amount online_weight_minimum; + unsigned online_weight_quorom; unsigned password_fanout; unsigned io_threads; unsigned work_threads; @@ -452,7 +458,7 @@ public: class node_observers { public: - rai::observer_set, rai::process_return const &> blocks; + rai::observer_set, rai::account const &, rai::uint128_t const &, bool> blocks; rai::observer_set wallet; rai::observer_set, rai::endpoint const &> vote; rai::observer_set account_balance; @@ -477,14 +483,6 @@ public: std::mutex mutex; std::unordered_set active; }; -class block_processor_item -{ -public: - block_processor_item (std::shared_ptr); - block_processor_item (std::shared_ptr, bool); - std::shared_ptr block; - bool force; -}; // Processing blocks is a potentially long IO operation // This class isolates block insertion from other operations like servicing network operations class block_processor @@ -494,19 +492,23 @@ public: ~block_processor (); void stop (); void flush (); - void add (rai::block_processor_item const &); - void process_receive_many (rai::block_processor_item const &); - void process_receive_many (std::deque &); - rai::process_return process_receive_one (MDB_txn *, std::shared_ptr); + void add (std::shared_ptr); + void force (std::shared_ptr); + bool should_log (); + bool have_blocks (); void process_blocks (); + rai::process_return process_receive_one (MDB_txn *, std::shared_ptr); private: + void process_receive_many (std::unique_lock &); bool stopped; - bool idle; - std::deque blocks; - std::mutex mutex; + bool active; + std::chrono::steady_clock::time_point next_log; + std::deque> blocks; + std::deque> forced; std::condition_variable condition; rai::node & node; + std::mutex mutex; }; class node : public std::enable_shared_from_this { @@ -547,6 +549,7 @@ public: uint64_t generate_work (rai::uint256_union const &); void generate_work (rai::uint256_union const &, std::function); void add_initial_peers (); + void block_confirm (std::shared_ptr); boost::asio::io_service & service; rai::node_config config; rai::alarm & alarm; diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 982cbe54..ae1af225 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -141,8 +141,8 @@ void rai::rpc::start () } acceptor.listen (); - node.observers.blocks.add ([this](std::shared_ptr block_a, rai::process_return const & result_a) { - observer_action (result_a.account); + node.observers.blocks.add ([this](std::shared_ptr block_a, rai::account const & account_a, rai::uint128_t const &, bool) { + observer_action (account_a); }); accept (); @@ -899,6 +899,32 @@ void rai::rpc_handler::block () } } +void rai::rpc_handler::block_confirm () +{ + std::string hash_text (request.get ("hash")); + rai::block_hash hash_l; + if (!hash_l.decode_hex (hash_text)) + { + rai::transaction transaction (node.store.environment, nullptr, false); + auto block_l (node.store.block_get (transaction, hash_l)); + if (block_l != nullptr) + { + node.block_confirm (std::move (block_l)); + boost::property_tree::ptree response_l; + response_l.put ("started", "1"); + response (response_l); + } + else + { + error_response (response, "Block not found"); + } + } + else + { + error_response (response, "Invalid block hash"); + } +} + void rai::rpc_handler::blocks () { std::vector hashes; @@ -937,6 +963,7 @@ void rai::rpc_handler::blocks_info () { const bool pending = request.get ("pending", false); const bool source = request.get ("source", false); + const bool balance = request.get ("balance", false); std::vector hashes; boost::property_tree::ptree response_l; boost::property_tree::ptree blocks; @@ -983,6 +1010,11 @@ void rai::rpc_handler::blocks_info () entry.put ("source_account", "0"); } } + if (balance) + { + auto balance (node.ledger.balance (transaction, hash)); + entry.put ("balance", balance.convert_to ()); + } blocks.push_back (std::make_pair (hash_text, entry)); } else @@ -1125,7 +1157,6 @@ void rai::rpc_handler::block_create () prv.data.clear (); rai::uint256_union previous (0); rai::uint128_union balance (0); - rai::uint256_union link (0); if (wallet != 0 && account != 0) { auto existing (node.wallets.items.find (wallet)); @@ -1184,6 +1215,7 @@ void rai::rpc_handler::block_create () error_response (response, "Bad balance number"); } } + rai::uint256_union link (0); boost::optional link_text (request.get_optional ("link")); if (link_text.is_initialized ()) { @@ -1197,20 +1229,48 @@ void rai::rpc_handler::block_create () } } } + else + { + // Retrieve link from source or destination + link = source.is_zero () ? destination : source; + } if (prv.data != 0) { rai::uint256_union pub; ed25519_publickey (prv.data.bytes.data (), pub.bytes.data ()); + // Fetching account balance & previous for send blocks (if aren't given directly) + if (!previous_text.is_initialized () && !balance_text.is_initialized ()) + { + rai::transaction transaction (node.store.environment, nullptr, false); + previous = node.ledger.latest (transaction, pub); + balance = node.ledger.account_balance (transaction, pub); + } + // Double check current balance if previous block is specified + else if (previous_text.is_initialized () && balance_text.is_initialized () && type == "send") + { + rai::transaction transaction (node.store.environment, nullptr, false); + if (node.store.block_exists (transaction, previous) && node.store.block_balance (transaction, previous) != balance.number ()) + { + error_response (response, "Balance mismatch for previous block"); + } + } + // Check for incorrect account key + if (account_text.is_initialized ()) + { + if (account != pub) + { + error_response (response, "Incorrect key for given account"); + } + } if (type == "state") { - if (!account.is_zero () && previous_text.is_initialized () && !representative.is_zero () && !balance.is_zero () && link_text.is_initialized ()) + if (previous_text.is_initialized () && !representative.is_zero () && (!link.is_zero () || link_text.is_initialized ())) { if (work == 0) { work = node.generate_work (previous.is_zero () ? pub : previous); } - - rai::state_block state (account, previous, representative, balance, link, prv, pub, work); + rai::state_block state (pub, previous, representative, balance, link, prv, pub, work); boost::property_tree::ptree response_l; response_l.put ("hash", state.hash ().to_string ()); std::string contents; @@ -1220,7 +1280,7 @@ void rai::rpc_handler::block_create () } else { - error_response (response, "Account, previous, representative, balance, and link are required"); + error_response (response, "Previous, representative, final balance and link (source or destination) are required"); } } else if (type == "open") @@ -1697,7 +1757,7 @@ public: { tree.put ("type", "send"); } - tree.put ("account", block_a.hashables.account.to_account ()); + tree.put ("account", block_a.hashables.link.to_account ()); tree.put ("amount", (previous_balance - balance).convert_to ()); } else @@ -1790,6 +1850,11 @@ void rai::rpc_handler::account_history () if (!entry.empty ()) { entry.put ("hash", hash.to_string ()); + if (output_raw) + { + entry.put ("work", rai::to_string_hex (block->block_work ())); + entry.put ("signature", block->block_signature ().to_string ()); + } history.push_back (std::make_pair ("", entry)); } --count; @@ -2324,14 +2389,14 @@ void rai::rpc_handler::payment_begin () wallet->free_accounts.erase (existing); if (wallet->store.find (transaction, account) == wallet->store.end ()) { - BOOST_LOG (node.log) << boost::str (boost::format ("Transaction wallet %1% externally modified listing account %1% as free but no longer exists") % id.to_string () % account.to_account ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Transaction wallet %1% externally modified listing account %2% as free but no longer exists") % id.to_string () % account.to_account ()); account.clear (); } else { if (!node.ledger.account_balance (transaction, account).is_zero ()) { - BOOST_LOG (node.log) << boost::str (boost::format ("Skipping account %1% for use as a transaction account since it's balance isn't zero") % account.to_account ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Skipping account %1% for use as a transaction account: non-zero balance") % account.to_account ()); account.clear (); } } @@ -2519,7 +2584,16 @@ void rai::rpc_handler::process () { case rai::process_result::progress: { - node.observers.blocks (block_a, result); + rai::transaction transaction (node.store.environment, nullptr, false); + auto account (node.ledger.account (transaction, hash)); + auto amount (node.ledger.amount (transaction, hash)); + bool is_state_send (false); + if (auto state = dynamic_cast (block_a.get ())) + { + rai::transaction transaction (node.store.environment, nullptr, false); + is_state_send = node.ledger.is_send (transaction, *state); + } + node.observers.blocks (block_a, account, amount, is_state_send); boost::property_tree::ptree response_l; response_l.put ("hash", hash.to_string ()); response (response_l); @@ -4558,6 +4632,10 @@ void rai::rpc_handler::process_request () { block (); } + else if (action == "block_confirm") + { + block_confirm (); + } else if (action == "blocks") { blocks (); diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index 71ff02a8..d63955cd 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -133,6 +133,7 @@ public: void accounts_pending (); void available_supply (); void block (); + void block_confirm (); void blocks (); void blocks_info (); void block_account (); diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 55d84fb1..9622b362 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -915,7 +915,8 @@ std::shared_ptr rai::wallet::receive_action (rai::block const & send node.generate_work (*block); } node.block_arrival.add (block->hash ()); - node.block_processor.process_receive_many (block); + node.block_processor.add (block); + node.block_processor.flush (); if (generate_work_a) { auto hash (block->hash ()); @@ -965,7 +966,8 @@ std::shared_ptr rai::wallet::change_action (rai::account const & sou node.generate_work (*block); } node.block_arrival.add (block->hash ()); - node.block_processor.process_receive_many (block); + node.block_processor.add (block); + node.block_processor.flush (); if (generate_work_a) { auto hash (block->hash ()); @@ -1058,7 +1060,8 @@ std::shared_ptr rai::wallet::send_action (rai::account const & sourc node.generate_work (*block); } node.block_arrival.add (block->hash ()); - node.block_processor.process_receive_many (block); + node.block_processor.add (block); + node.block_processor.flush (); auto hash (block->hash ()); auto this_l (shared_from_this ()); node.wallets.queue_wallet_action (rai::wallets::generate_priority, [this_l, source_a, hash] { diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 57e77b01..0871a572 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -1099,18 +1099,17 @@ void rai_qt::wallet::start () this_l->push_main_stack (this_l->send_blocks_window); } }); - node.observers.blocks.add ([this_w](std::shared_ptr block_a, rai::process_return const & result_a) { + node.observers.blocks.add ([this_w](std::shared_ptr block_a, rai::account const & account_a, rai::uint128_t const & amount_a, bool) { if (auto this_l = this_w.lock ()) { - auto account (result_a.account); - this_l->application.postEvent (&this_l->processor, new eventloop_event ([this_w, block_a, account]() { + this_l->application.postEvent (&this_l->processor, new eventloop_event ([this_w, block_a, account_a]() { if (auto this_l = this_w.lock ()) { - if (this_l->wallet_m->exists (account)) + if (this_l->wallet_m->exists (account_a)) { this_l->accounts.refresh (); } - if (account == this_l->account) + if (account_a == this_l->account) { this_l->history.refresh (); } From 61373c4a7542794623d6c99ff788a02b5e84d888 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Sun, 29 Apr 2018 09:57:08 +0100 Subject: [PATCH 2/4] Eliminating duplicate quorum check code. --- rai/core_test/node.cpp | 12 ++++++------ rai/core_test/rpc.cpp | 4 ++-- rai/ledger.hpp | 3 ++- rai/node/node.cpp | 31 +++++++++++++++---------------- rai/node/node.hpp | 3 ++- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index 991d9828..f26d2082 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -185,7 +185,7 @@ TEST (node, quick_confirm) rai::block_hash previous (system.nodes[0]->latest (rai::test_genesis_key.pub)); system.wallet (0)->insert_adhoc (key.prv); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - auto send (std::make_shared (previous, key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (previous))); + auto send (std::make_shared (previous, key.pub, system.nodes[0]->delta () + 1, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (previous))); system.nodes[0]->process_active (send); auto iterations (0); while (system.nodes[0]->balance (key.pub).is_zero ()) @@ -196,7 +196,7 @@ TEST (node, quick_confirm) } } -TEST (node, node_receive_quorom) +TEST (node, node_receive_quorum) { rai::system system (24000, 1); rai::keypair key; @@ -219,7 +219,7 @@ TEST (node, node_receive_quorom) } ASSERT_TRUE (system.nodes[0]->balance (key.pub).is_zero ()); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - system.nodes [0]->block_confirm (send); + system.nodes[0]->block_confirm (send); while (system.nodes[0]->balance (key.pub).is_zero ()) { system.poll (); @@ -1486,10 +1486,10 @@ TEST (node, online_reps) { rai::system system (24000, 2); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - ASSERT_EQ (system.nodes [1]->config.online_weight_minimum.number (), system.nodes[1]->online_reps.online_stake ()); + ASSERT_EQ (system.nodes[1]->config.online_weight_minimum.number (), system.nodes[1]->online_reps.online_stake ()); system.wallet (0)->send_action (rai::test_genesis_key.pub, rai::test_genesis_key.pub, rai::Gxrb_ratio); auto iterations (0); - while (system.nodes[1]->online_reps.online_stake () == system.nodes [1]->config.online_weight_minimum.number ()) + while (system.nodes[1]->online_reps.online_stake () == system.nodes[1]->config.online_weight_minimum.number ()) { system.poll (); ++iterations; @@ -1524,7 +1524,7 @@ TEST (node, confirm_quorom) rai::system system (24000, 1); rai::genesis genesis; system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - system.nodes [0]->ledger.state_block_parse_canary = genesis.hash (); + system.nodes[0]->ledger.state_block_parse_canary = genesis.hash (); // Put greater than online_weight_minimum in pending so quorom can't be reached auto send1 (std::make_shared (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.nodes[0]->generate_work (genesis.hash ()))); { diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index a76a1e39..0c468eb4 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -3451,10 +3451,10 @@ TEST (rpc, online_reps) { rai::system system (24000, 2); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - ASSERT_TRUE (system.nodes[1]->online_reps.online_stake () == system.nodes [1]->config.online_weight_minimum.number ()); + ASSERT_TRUE (system.nodes[1]->online_reps.online_stake () == system.nodes[1]->config.online_weight_minimum.number ()); system.wallet (0)->send_action (rai::test_genesis_key.pub, rai::test_genesis_key.pub, rai::Gxrb_ratio); auto iterations (0); - while (system.nodes[1]->online_reps.online_stake () == system.nodes [1]->config.online_weight_minimum.number ()) + while (system.nodes[1]->online_reps.online_stake () == system.nodes[1]->config.online_weight_minimum.number ()) { system.poll (); ++iterations; diff --git a/rai/ledger.hpp b/rai/ledger.hpp index b467a888..c779cdc6 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -12,13 +12,14 @@ public: size_t operator() (std::shared_ptr const &) const; bool operator() (std::shared_ptr const &, std::shared_ptr const &) const; }; +using tally_t = std::map, std::greater>; class ledger { public: ledger (rai::block_store &, rai::block_hash const & = 0, rai::block_hash const & = 0); std::pair> winner (MDB_txn *, rai::votes const & votes_a); // Map of weight -> associated block, ordered greatest to least - std::map, std::greater> tally (MDB_txn *, rai::votes const &); + rai::tally_t tally (MDB_txn *, rai::votes const &); rai::account account (MDB_txn *, rai::block_hash const &); rai::uint128_t amount (MDB_txn *, rai::block_hash const &); rai::uint128_t balance (MDB_txn *, rai::block_hash const &); diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 61054ccf..75f8af31 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -794,7 +794,7 @@ peering_port (peering_port_a), logging (logging_a), bootstrap_fraction_numerator (1), receive_minimum (rai::xrb_ratio), -online_weight_minimum (60 * rai::Gxrb_ratio), +online_weight_minimum (60000 * rai::Gxrb_ratio), online_weight_quorom (50), password_fanout (1024), io_threads (std::max (4, std::thread::hardware_concurrency ())), @@ -2396,6 +2396,12 @@ void rai::node::block_confirm (std::shared_ptr block_a) network.broadcast_confirm_req (block_a); } +rai::uint128_t rai::node::delta () +{ + auto result ((online_reps.online_stake () / 100) * config.online_weight_quorom); + return result; +} + namespace { class confirmed_visitor : public rai::block_visitor @@ -3002,15 +3008,9 @@ void rai::election::confirm_once (MDB_txn * transaction_a) { auto tally_l (node.ledger.tally (transaction_a, votes)); assert (tally_l.size () > 0); + auto exceeded_min_threshold = have_quorum (tally_l); auto winner (tally_l.begin ()); auto block_l (winner->second); - rai::uint128_t total (0); - for (auto & i : tally_l) - { - total += i.first; - } - auto quorom_minimum ((total / 100) * node.config.online_weight_quorom); - auto exceeded_min_threshold = total > node.config.online_weight_minimum.number () && winner->first > quorom_minimum; if (node.config.logging.vote_logging () || !votes.uncontested ()) { BOOST_LOG (node.log) << boost::str (boost::format ("Vote tally for root %1%") % status.winner->root ().to_string ()); @@ -3050,22 +3050,21 @@ void rai::election::confirm_once (MDB_txn * transaction_a) } } -bool rai::election::have_quorum (MDB_txn * transaction_a) +bool rai::election::have_quorum (rai::tally_t const & tally_a) { - auto tally_l (node.ledger.tally (transaction_a, votes)); - assert (tally_l.size () > 0); - auto i (tally_l.begin ()); + auto i (tally_a.begin ()); auto first (i->first); ++i; - auto second (i != tally_l.end () ? i->first : 0); - auto delta ((node.online_reps.online_stake () / 100) * node.config.online_weight_quorom); - auto result (tally_l.begin ()->first > (second + delta)); + auto second (i != tally_a.end () ? i->first : 0); + auto delta_l (node.delta ()); + auto result (tally_a.begin ()->first > (second + delta_l)); return result; } void rai::election::confirm_if_quorum (MDB_txn * transaction_a) { - auto quorum (have_quorum (transaction_a)); + auto tally_l (node.ledger.tally (transaction_a, votes)); + auto quorum (have_quorum (tally_l)); if (quorum) { confirm_once (transaction_a); diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 119c4f4b..042f68b4 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -51,7 +51,7 @@ public: election (MDB_txn *, rai::node &, std::shared_ptr, std::function, bool)> const &); bool vote (std::shared_ptr); // Check if we have vote quorum - bool have_quorum (MDB_txn *); + bool have_quorum (rai::tally_t const &); // Tell the network our view of the winner void broadcast_winner (); // Change our winner to agree with the network @@ -549,6 +549,7 @@ public: void generate_work (rai::uint256_union const &, std::function); void add_initial_peers (); void block_confirm (std::shared_ptr); + rai::uint128_t delta (); boost::asio::io_service & service; rai::node_config config; rai::alarm & alarm; From bf54ffc7fe9679d194fa229319ddbc45a8180563 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Sun, 29 Apr 2018 10:13:44 +0100 Subject: [PATCH 3/4] Checking if resolved at call site instead of within callback. --- rai/core_test/node.cpp | 3 ++- rai/node/bootstrap.cpp | 25 +++++++++++-------------- rai/node/node.cpp | 32 ++++++++++++++++++-------------- rai/node/node.hpp | 8 ++++---- rai/node/wallet.cpp | 2 +- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index f26d2082..357346f8 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -1185,7 +1185,7 @@ TEST (node, rep_self_vote) auto & active (node0->active); { rai::transaction transaction (node0->store.environment, nullptr, true); - active.start (transaction, block0, [](std::shared_ptr, bool) {}); + active.start (transaction, block0); } auto existing (active.roots.find (block0->root ())); ASSERT_NE (active.roots.end (), existing); @@ -1467,6 +1467,7 @@ TEST (node, bootstrap_connection_scaling) auto & node1 (*system.nodes[0]); node1.bootstrap_initiator.bootstrap (); auto attempt (node1.bootstrap_initiator.current_attempt ()); + ASSERT_NE (nullptr, attempt); ASSERT_EQ (34, attempt->target_connections (25000)); ASSERT_EQ (4, attempt->target_connections (0)); ASSERT_EQ (64, attempt->target_connections (50000)); diff --git a/rai/node/bootstrap.cpp b/rai/node/bootstrap.cpp index 83f6151e..0a80876f 100644 --- a/rai/node/bootstrap.cpp +++ b/rai/node/bootstrap.cpp @@ -1043,22 +1043,19 @@ void rai::bootstrap_attempt::process_fork (MDB_txn * transaction_a, std::shared_ if (ledger_block) { std::weak_ptr this_w (shared_from_this ()); - if (!node->active.start (transaction_a, std::make_pair (ledger_block, block_a), [this_w, root](std::shared_ptr, bool resolved) { + if (!node->active.start (transaction_a, std::make_pair (ledger_block, block_a), [this_w, root](std::shared_ptr) { if (auto this_l = this_w.lock ()) { - if (resolved) - { - rai::transaction transaction (this_l->node->store.environment, nullptr, false); - auto account (this_l->node->ledger.store.frontier_get (transaction, root)); - if (!account.is_zero ()) - { - this_l->requeue_pull (rai::pull_info (account, root, root)); - } - else if (this_l->node->ledger.store.account_exists (transaction, root)) - { - this_l->requeue_pull (rai::pull_info (root, rai::block_hash (0), rai::block_hash (0))); - } - } + rai::transaction transaction (this_l->node->store.environment, nullptr, false); + auto account (this_l->node->ledger.store.frontier_get (transaction, root)); + if (!account.is_zero ()) + { + this_l->requeue_pull (rai::pull_info (account, root, root)); + } + else if (this_l->node->ledger.store.account_exists (transaction, root)) + { + this_l->requeue_pull (rai::pull_info (root, rai::block_hash (0), rai::block_hash (0))); + } } })) { diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 75f8af31..543cc93d 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -2976,7 +2976,7 @@ std::shared_ptr rai::node::shared () return shared_from_this (); } -rai::election::election (MDB_txn * transaction_a, rai::node & node_a, std::shared_ptr block_a, std::function, bool)> const & confirmation_action_a) : +rai::election::election (MDB_txn * transaction_a, rai::node & node_a, std::shared_ptr block_a, std::function)> const & confirmation_action_a) : confirmation_action (confirmation_action_a), votes (block_a), node (node_a), @@ -3008,7 +3008,7 @@ void rai::election::confirm_once (MDB_txn * transaction_a) { auto tally_l (node.ledger.tally (transaction_a, votes)); assert (tally_l.size () > 0); - auto exceeded_min_threshold = have_quorum (tally_l); + auto have_quorum_l = have_quorum (tally_l); auto winner (tally_l.begin ()); auto block_l (winner->second); if (node.config.logging.vote_logging () || !votes.uncontested ()) @@ -3025,7 +3025,7 @@ void rai::election::confirm_once (MDB_txn * transaction_a) } if (!(*block_l == *status.winner)) { - if (exceeded_min_threshold) + if (have_quorum_l) { auto node_l (node.shared ()); node_l->block_processor.force (block_l); @@ -3037,16 +3037,20 @@ void rai::election::confirm_once (MDB_txn * transaction_a) } } status.tally = winner->first; - auto winner_l (status.winner); - auto node_l (node.shared ()); - auto confirmation_action_l (confirmation_action); - node.background ([node_l, winner_l, confirmation_action_l, exceeded_min_threshold]() { - if (exceeded_min_threshold) - { + if (have_quorum_l) + { + auto winner_l (status.winner); + auto node_l (node.shared ()); + auto confirmation_action_l (confirmation_action); + node.background ([node_l, winner_l, confirmation_action_l]() { node_l->process_confirmed (winner_l); - } - confirmation_action_l (winner_l, exceeded_min_threshold); - }); + confirmation_action_l (winner_l); + }); + } + else + { + BOOST_LOG (node.log) << boost::str (boost::format ("Insufficient quorum for block %1%") % status.winner->hash ().to_string ()); + } } } @@ -3233,12 +3237,12 @@ void rai::active_transactions::stop () roots.clear (); } -bool rai::active_transactions::start (MDB_txn * transaction_a, std::shared_ptr block_a, std::function, bool)> const & confirmation_action_a) +bool rai::active_transactions::start (MDB_txn * transaction_a, std::shared_ptr block_a, std::function)> const & confirmation_action_a) { return start (transaction_a, std::make_pair (block_a, nullptr), confirmation_action_a); } -bool rai::active_transactions::start (MDB_txn * transaction_a, std::pair, std::shared_ptr> blocks_a, std::function, bool)> const & confirmation_action_a) +bool rai::active_transactions::start (MDB_txn * transaction_a, std::pair, std::shared_ptr> blocks_a, std::function)> const & confirmation_action_a) { assert (blocks_a.first != nullptr); std::lock_guard lock (mutex); diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 042f68b4..9bf53e3b 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -44,11 +44,11 @@ public: }; class election : public std::enable_shared_from_this { - std::function, bool)> confirmation_action; + std::function)> confirmation_action; void confirm_once (MDB_txn *); public: - election (MDB_txn *, rai::node &, std::shared_ptr, std::function, bool)> const &); + election (MDB_txn *, rai::node &, std::shared_ptr, std::function)> const &); bool vote (std::shared_ptr); // Check if we have vote quorum bool have_quorum (rai::tally_t const &); @@ -83,11 +83,11 @@ public: active_transactions (rai::node &); // Start an election for a block // Call action with confirmed block, may be different than what we started with - bool start (MDB_txn *, std::shared_ptr, std::function, bool)> const & = [](std::shared_ptr, bool) {}); + bool start (MDB_txn *, std::shared_ptr, std::function)> const & = [](std::shared_ptr) {}); // Also supply alternatives to block, to confirm_req reps with if the boolean argument is true // Should only be used for old elections // The first block should be the one in the ledger - bool start (MDB_txn *, std::pair, std::shared_ptr>, std::function, bool)> const & = [](std::shared_ptr, bool) {}); + bool start (MDB_txn *, std::pair, std::shared_ptr>, std::function)> const & = [](std::shared_ptr) {}); // If this returns true, the vote is a replay // If this returns false, the vote may or may not be a replay bool vote (std::shared_ptr); diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 9622b362..6c3b8551 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -1229,7 +1229,7 @@ public: std::shared_ptr block_l (wallet->node.store.block_get (transaction, info.head)); wallet->node.background ([this_l, account, block_l] { rai::transaction transaction (this_l->wallet->node.store.environment, nullptr, true); - this_l->wallet->node.active.start (transaction, block_l, [this_l, account](std::shared_ptr, bool) { + this_l->wallet->node.active.start (transaction, block_l, [this_l, account](std::shared_ptr) { // If there were any forks for this account they've been rolled back and we can receive anything remaining from this account this_l->receive_all (account); }); From a26724a0a3a4fa4716c63a2bb1084002cc63429b Mon Sep 17 00:00:00 2001 From: clemahieu Date: Mon, 30 Apr 2018 10:53:34 +0100 Subject: [PATCH 4/4] Logging quorom weight received. --- rai/node/node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 543cc93d..caaf54c6 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -3049,7 +3049,7 @@ void rai::election::confirm_once (MDB_txn * transaction_a) } else { - BOOST_LOG (node.log) << boost::str (boost::format ("Insufficient quorum for block %1%") % status.winner->hash ().to_string ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Insufficient quorum for block %1% %2%") % status.winner->hash ().to_string () % status.tally.number ().convert_to ()); } } }