diff --git a/libraries/chain/include/graphene/chain/operations.hpp b/libraries/chain/include/graphene/chain/operations.hpp index 895186e1..300dfdef 100644 --- a/libraries/chain/include/graphene/chain/operations.hpp +++ b/libraries/chain/include/graphene/chain/operations.hpp @@ -133,10 +133,8 @@ namespace graphene { namespace chain { * @brief Claim a balance in a @ref balanc_object * * This operation is used to claim the balance in a given @ref balance_object. If the balance object contains a - * vesting balance, @ref total_claimed must be set to zero, and all available vested funds will be claimed. If the - * object contains a non-vesting balance, @ref total_claimed must be the full balance of the object. - * - * This operation returns the total amount claimed. + * vesting balance, @ref total_claimed must not exceed @ref balance_object::available at the time of evaluation. If + * the object contains a non-vesting balance, @ref total_claimed must be the full balance of the object. */ struct balance_claim_operation { @@ -151,13 +149,12 @@ namespace graphene { namespace chain { share_type calculate_fee(const fee_schedule_type& k)const { return 0; } void validate()const; - void get_balance_delta(balance_accumulator& acc, const operation_result& result)const { - acc.adjust(deposit_to_account, result.get()); + void get_balance_delta(balance_accumulator& acc, const operation_result& = asset())const { + acc.adjust(deposit_to_account, total_claimed); acc.adjust(fee_payer(), -fee); } }; - /** * @ingroup operations */ @@ -455,17 +452,18 @@ namespace graphene { namespace chain { * be unique with high probability as long as the generating host has a high-resolution clock OR a strong source * of entropy for generating private keys. */ - uint64_t nonce; + uint64_t nonce; /** * This field contains the AES encrypted packed @ref memo_message */ vector message; - void set_message( const fc::ecc::private_key& priv, - const fc::ecc::public_key& pub, const string& msg ); + /// @note custom_nonce is for debugging only; do not set to a nonzero value in production + void set_message(const fc::ecc::private_key& priv, + const fc::ecc::public_key& pub, const string& msg, uint64_t custom_nonce = 0); - std::string get_message( const fc::ecc::private_key& priv, - const fc::ecc::public_key& pub )const; + std::string get_message(const fc::ecc::private_key& priv, + const fc::ecc::public_key& pub)const; }; /** diff --git a/libraries/chain/operations.cpp b/libraries/chain/operations.cpp index aec48d76..e7beff65 100644 --- a/libraries/chain/operations.cpp +++ b/libraries/chain/operations.cpp @@ -840,15 +840,19 @@ share_type vesting_balance_withdraw_operation::calculate_fee(const fee_schedule_ return k.vesting_balance_withdraw_fee; } -void memo_data::set_message( const fc::ecc::private_key& priv, - const fc::ecc::public_key& pub, const string& msg ) +void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::public_key& pub, + const string& msg, uint64_t custom_nonce) { if( from != public_key_type() ) { - uint64_t entropy = fc::sha224::hash(fc::ecc::private_key::generate())._hash[0]; - entropy <<= 32; - entropy &= 0xff00000000000000; - nonce = (fc::time_point::now().time_since_epoch().count() & 0x00ffffffffffffff) | entropy; + if( custom_nonce == 0 ) + { + uint64_t entropy = fc::sha224::hash(fc::ecc::private_key::generate())._hash[0]; + entropy <<= 32; + entropy &= 0xff00000000000000; + nonce = (fc::time_point::now().time_since_epoch().count() & 0x00ffffffffffffff) | entropy; + } else + nonce = custom_nonce; auto secret = priv.get_shared_secret(pub); auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str()); string text = memo_message(digest_type::hash(msg)._hash[0], msg).serialize(); @@ -856,13 +860,13 @@ void memo_data::set_message( const fc::ecc::private_key& priv, } else { - auto text = memo_message( 0, msg ).serialize(); + auto text = memo_message(0, msg).serialize(); message = vector(text.begin(), text.end()); } } -string memo_data::get_message( const fc::ecc::private_key& priv, - const fc::ecc::public_key& pub )const +string memo_data::get_message(const fc::ecc::private_key& priv, + const fc::ecc::public_key& pub)const { if( from != public_key_type() ) { diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index 1bd0ce16..56f4cf96 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -174,7 +175,15 @@ BOOST_AUTO_TEST_CASE( memo_test ) auto receiver = generate_private_key("2"); m.from = sender.get_public_key(); m.to = receiver.get_public_key(); - m.set_message(sender, receiver.get_public_key(), "Hello, world!"); + m.set_message(sender, receiver.get_public_key(), "Hello, world!", 12345); + + decltype(fc::digest(m)) hash("8de72a07d093a589f574460deb19023b4aff354b561eb34590d9f4629f51dbf3"); + if( fc::digest(m) != hash ) + { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } BOOST_CHECK_EQUAL(m.get_message(receiver, sender.get_public_key()), "Hello, world!"); } FC_LOG_AND_RETHROW() } @@ -319,4 +328,9 @@ BOOST_AUTO_TEST_CASE( data_fees ) BOOST_CHECK_EQUAL(fs.total_data_fee(keys, x), (fc::raw::pack_size(keys) + fc::raw::pack_size(x)) / 1024 * 10); } +BOOST_AUTO_TEST_CASE( exceptions ) +{ + BOOST_CHECK_THROW(FC_THROW_EXCEPTION(invalid_claim_amount, "Etc"), invalid_claim_amount); +} + BOOST_AUTO_TEST_SUITE_END()