From 9032a0528baa9076d8973072e16793976897a789 Mon Sep 17 00:00:00 2001 From: j-berman Date: Mon, 28 Feb 2022 02:55:41 -0500 Subject: [PATCH 1/2] Update fee calc to use CLSAG + other minor changes --- README.md | 1 + src/monero_fee_utils.cpp | 27 +++++++++++++++------------ src/monero_fee_utils.hpp | 8 ++++---- src/monero_transfer_utils.cpp | 13 +++++++------ src/serial_bridge_index.cpp | 9 ++++++--- test/test_all.cpp | 13 ++++++++----- 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 5fe2132..206502f 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,7 @@ Useful for displaying an estimated fee – To obtain exact fees, see "Creating a * `n_outputs: UInt32String` * `extra_size: UInt32String` * `bulletproof: BoolString` + * `clsag: BooLString` * Returns: `retVal: UInt32String` diff --git a/src/monero_fee_utils.cpp b/src/monero_fee_utils.cpp index c848825..4607489 100644 --- a/src/monero_fee_utils.cpp +++ b/src/monero_fee_utils.cpp @@ -64,7 +64,7 @@ uint64_t monero_fee_utils::estimated_tx_network_fee( ) { uint64_t fee_multiplier = get_fee_multiplier(priority, default_priority(), get_fee_algorithm(use_fork_rules_fn), use_fork_rules_fn); std::vector extra; // blank extra - size_t est_tx_size = estimate_rct_tx_size(2, fixed_mixinsize(), 2, extra.size(), true/*bulletproof*/); // typically ~14kb post-rct, pre-bulletproofs + size_t est_tx_size = estimate_rct_tx_size(2, fixed_mixinsize(), 2, extra.size(), true/*bulletproof*/, true/*clsag*/); // typically ~14kb post-rct, pre-bulletproofs uint64_t estimated_fee = calculate_fee_from_size(base_fee, est_tx_size, fee_multiplier); // return estimated_fee; @@ -137,7 +137,7 @@ int monero_fee_utils::get_fee_algorithm(use_fork_rules_fn_type use_fork_rules_fn return 1; return 0; } -size_t monero_fee_utils::estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof) +size_t monero_fee_utils::estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag) { size_t size = 0; @@ -171,8 +171,11 @@ size_t monero_fee_utils::estimate_rct_tx_size(int n_inputs, int mixin, int n_out else size += (2*64*32+32+64*32) * n_outputs; - // MGs - size += n_inputs * (64 * (mixin+1) + 32); + // MGs/CLSAGs + if (clsag) + size += n_inputs * (32 * (mixin+1) + 64); + else + size += n_inputs * (64 * (mixin+1) + 32); // mixRing - not serialized, can be reconstructed /* size += 2 * 32 * (mixin+1) * n_inputs; */ @@ -180,7 +183,7 @@ size_t monero_fee_utils::estimate_rct_tx_size(int n_inputs, int mixin, int n_out // pseudoOuts size += 32 * n_inputs; // ecdhInfo - size += 2 * 32 * n_outputs; + size += 8 * n_outputs; // outPk - only commitment is saved size += 32 * n_outputs; // txnFee @@ -189,16 +192,16 @@ size_t monero_fee_utils::estimate_rct_tx_size(int n_inputs, int mixin, int n_out LOG_PRINT_L2("estimated " << (bulletproof ? "bulletproof" : "borromean") << " rct tx size for " << n_inputs << " inputs with ring size " << (mixin+1) << " and " << n_outputs << " outputs: " << size << " (" << ((32 * n_inputs/*+1*/) + 2 * 32 * (mixin+1) * n_inputs + 32 * n_outputs) << " saved)"); return size; } -size_t monero_fee_utils::estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof) +size_t monero_fee_utils::estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag) { if (use_rct) - return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof); + return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag); else return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size; } -uint64_t monero_fee_utils::estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof) +uint64_t monero_fee_utils::estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag) { - size_t size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof); + size_t size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag); if (use_rct && bulletproof && n_outputs > 2) { const uint64_t bp_base = 368; @@ -213,16 +216,16 @@ uint64_t monero_fee_utils::estimate_tx_weight(bool use_rct, int n_inputs, int mi } return size; } -uint64_t monero_fee_utils::estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, uint64_t base_fee, uint64_t fee_multiplier, uint64_t fee_quantization_mask) +uint64_t monero_fee_utils::estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, uint64_t base_fee, uint64_t fee_multiplier, uint64_t fee_quantization_mask) { if (use_per_byte_fee) { - const size_t estimated_tx_weight = estimate_tx_weight(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof); + const size_t estimated_tx_weight = estimate_tx_weight(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag); return calculate_fee_from_weight(base_fee, estimated_tx_weight, fee_multiplier, fee_quantization_mask); } else { - const size_t estimated_tx_size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof); + const size_t estimated_tx_size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag); return calculate_fee_from_size(base_fee, estimated_tx_size, fee_multiplier); } } diff --git a/src/monero_fee_utils.hpp b/src/monero_fee_utils.hpp index 7ba1d28..042b1cf 100644 --- a/src/monero_fee_utils.hpp +++ b/src/monero_fee_utils.hpp @@ -57,16 +57,16 @@ namespace monero_fee_utils int get_fee_algorithm(use_fork_rules_fn_type use_fork_rules_fn); uint64_t get_base_fee(uint64_t fee_per_b); // - uint64_t estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, uint64_t base_fee, uint64_t fee_multiplier, uint64_t fee_quantization_mask); + uint64_t estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, uint64_t base_fee, uint64_t fee_multiplier, uint64_t fee_quantization_mask); // uint64_t calculate_fee_from_weight(uint64_t base_fee, uint64_t weight, uint64_t fee_multiplier, uint64_t fee_quantization_mask); uint64_t calculate_fee(bool use_per_byte_fee, const cryptonote::transaction &tx, size_t blob_size, uint64_t base_fee, uint64_t fee_multiplier, uint64_t fee_quantization_mask); // /*Added*/ uint64_t calculate_fee_from_size(uint64_t fee_per_b, size_t bytes, uint64_t fee_multiplier); // - size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof); - uint64_t estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof); - size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof); + size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag); + uint64_t estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag); + size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag); uint64_t estimated_tx_network_fee( // convenience function for size + calc uint64_t fee_per_b, uint32_t priority, // when priority=0, falls back to monero_fee_utils::default_priority() diff --git a/src/monero_transfer_utils.cpp b/src/monero_transfer_utils.cpp index d158984..7204d07 100644 --- a/src/monero_transfer_utils.cpp +++ b/src/monero_transfer_utils.cpp @@ -262,6 +262,7 @@ void monero_transfer_utils::send_step1__prepare_params_for_get_decoys( // bool use_rct = true; bool bulletproof = true; + bool clsag = true; // std::vector extra; CreateTransactionErrorCode tx_extra__code = _add_pid_to_tx_extra(payment_id_string, extra); @@ -274,9 +275,9 @@ void monero_transfer_utils::send_step1__prepare_params_for_get_decoys( // uint64_t attempt_at_min_fee; if (passedIn_attemptAt_fee == none) { - attempt_at_min_fee = estimate_fee(true/*use_per_byte_fee*/, true/*use_rct*/, 2/*est num inputs*/, fake_outs_count, 2, extra.size(), bulletproof, base_fee, fee_multiplier, fee_quantization_mask); - // opted to do this instead of `const uint64_t min_fee = (fee_multiplier * base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof));` - // TODO: estimate with 1 input or 2? + attempt_at_min_fee = estimate_fee(true/*use_per_byte_fee*/, true/*use_rct*/, 1/*est num inputs*/, fake_outs_count, 2, extra.size(), bulletproof, clsag, base_fee, fee_multiplier, fee_quantization_mask); + // use a minimum viabale estimate_fee() with 1 input. It would be better to under-shoot this estimate, and then need to use a higher fee from calculate_fee() because the estimate is too low, + // versus the worse alternative of over-estimating here and getting stuck using too high of a fee that leads to fingerprinting } else { attempt_at_min_fee = *passedIn_attemptAt_fee; } @@ -324,10 +325,10 @@ void monero_transfer_utils::send_step1__prepare_params_for_get_decoys( uint64_t needed_fee = estimate_fee( true/*use_per_byte_fee*/, use_rct, retVals.using_outs.size(), fake_outs_count, /*tx.dsts.size()*/1+1, extra.size(), - bulletproof, base_fee, fee_multiplier, fee_quantization_mask + bulletproof, clsag, base_fee, fee_multiplier, fee_quantization_mask ); // if newNeededFee < neededFee, use neededFee instead (should only happen on the 2nd or later times through (due to estimated fee being too low)) - if (needed_fee < attempt_at_min_fee) { + if (passedIn_attemptAt_fee != none && needed_fee < attempt_at_min_fee) { needed_fee = attempt_at_min_fee; } // @@ -362,7 +363,7 @@ void monero_transfer_utils::send_step1__prepare_params_for_get_decoys( needed_fee = estimate_fee( true/*use_per_byte_fee*/, use_rct, retVals.using_outs.size(), fake_outs_count, /*tx.dsts.size()*/1+1, extra.size(), - bulletproof, base_fee, fee_multiplier, fee_quantization_mask + bulletproof, clsag, base_fee, fee_multiplier, fee_quantization_mask ); total_incl_fees = sending_amount + needed_fee; // because fee changed } diff --git a/src/serial_bridge_index.cpp b/src/serial_bridge_index.cpp index 6c24665..22fe45a 100644 --- a/src/serial_bridge_index.cpp +++ b/src/serial_bridge_index.cpp @@ -343,6 +343,7 @@ string serial_bridge::estimate_fee(const string &args_string) int n_outputs = stoul(json_root.get("n_outputs")); size_t extra_size = stoul(json_root.get("extra_size")); bool bulletproof = json_root.get("bulletproof"); + bool clsag = json_root.get("clsag"); uint64_t base_fee = stoull(json_root.get("base_fee")); uint64_t fee_quantization_mask = stoull(json_root.get("fee_quantization_mask")); uint32_t priority = stoul(json_root.get("priority")); @@ -350,7 +351,7 @@ string serial_bridge::estimate_fee(const string &args_string) use_fork_rules_fn_type use_fork_rules_fn = monero_fork_rules::make_use_fork_rules_fn(fork_version); uint64_t fee_multiplier = monero_fee_utils::get_fee_multiplier(priority, monero_fee_utils::default_priority(), monero_fee_utils::get_fee_algorithm(use_fork_rules_fn), use_fork_rules_fn); // - uint64_t fee = monero_fee_utils::estimate_fee(use_per_byte_fee, use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, base_fee, fee_multiplier, fee_quantization_mask); + uint64_t fee = monero_fee_utils::estimate_fee(use_per_byte_fee, use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, base_fee, fee_multiplier, fee_quantization_mask); // std::ostringstream o; o << fee; @@ -372,8 +373,9 @@ string serial_bridge::estimate_tx_weight(const string &args_string) int n_outputs = stoul(json_root.get("n_outputs")); size_t extra_size = stoul(json_root.get("extra_size")); bool bulletproof = json_root.get("bulletproof"); + bool clsag = json_root.get("clsag"); // - uint64_t weight = monero_fee_utils::estimate_tx_weight(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof); + uint64_t weight = monero_fee_utils::estimate_tx_weight(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag); // std::ostringstream o; o << weight; @@ -394,7 +396,8 @@ string serial_bridge::estimate_rct_tx_size(const string &args_string) stoul(json_root.get("mixin")), stoul(json_root.get("n_outputs")), stoul(json_root.get("extra_size")), - json_root.get("bulletproof") + json_root.get("bulletproof"), + json_root.get("clsag") ); std::ostringstream o; o << size; diff --git a/test/test_all.cpp b/test/test_all.cpp index 7939da9..92ba2ec 100644 --- a/test/test_all.cpp +++ b/test/test_all.cpp @@ -338,7 +338,7 @@ BOOST_AUTO_TEST_CASE(bridge__transfers__send__amountWOnlyDusty) boost::property_tree::read_json(ret_stream, ret_tree); optional err_code = ret_tree.get_optional(ret_json_key__any__err_code()); BOOST_REQUIRE_MESSAGE(err_code == none, "Expected no error"); - BOOST_REQUIRE_MESSAGE(ret_tree.get("using_fee") == string("66290000"), "Expected using_fee of 66290000"); + BOOST_REQUIRE_MESSAGE(ret_tree.get("using_fee") == string("35190000"), "Expected using_fee of 35190000"); BOOST_REQUIRE_MESSAGE(ret_tree.get("final_total_wo_fee") == string("1000000"), "Expected final_total_wo_fee of 1000000"); } string DG_postsweep__unspent_outs_json = "{\"unspent_outs\":[{\"amount\":\"3000000000\",\"public_key\":\"41be1978f58cabf69a9bed5b6cb3c8d588621ef9b67602328da42a213ee42271\",\"index\":1,\"global_index\":7611174,\"rct\":\"86a2c9f1f8e66848cd99bfda7a14d4ac6c3525d06947e21e4e55fe42a368507eb5b234ccdd70beca8b1fc8de4f2ceb1374e0f1fd8810849e7f11316c2cc063060008ffa5ac9827b776993468df21af8c963d12148622354f950cbe1369a92a0c\",\"tx_id\":5334971,\"tx_hash\":\"9d37c7fdeab91abfd1e7e120f5c49eac17b7ac04a97a0c93b51c172115df21ea\",\"tx_pub_key\":\"bd703d7f37995cc7071fb4d2929594b5e2a4c27d2b7c68a9064500ca7bc638b8\"}]}"; @@ -895,7 +895,7 @@ BOOST_AUTO_TEST_CASE(bridged__estimated_tx_network_fee) BOOST_REQUIRE(fee_string != none); BOOST_REQUIRE((*fee_string).size() > 0); uint64_t fee = stoull(*fee_string); - BOOST_REQUIRE(fee == 330047330); + BOOST_REQUIRE(fee == 237333250); cout << "bridged__estimated_tx_network_fee: " << fee << endl; } BOOST_AUTO_TEST_CASE(bridged__estimate_fee) @@ -910,6 +910,7 @@ BOOST_AUTO_TEST_CASE(bridged__estimate_fee) root.put("n_outputs", "2"); root.put("extra_size", "0"); root.put("bulletproof", "true"); + root.put("clsag", "true"); root.put("base_fee", "24658"); root.put("fee_quantization_mask", "10000"); root.put("priority", "2"); @@ -928,7 +929,7 @@ BOOST_AUTO_TEST_CASE(bridged__estimate_fee) BOOST_REQUIRE(fee_string != none); BOOST_REQUIRE((*fee_string).size() > 0); uint64_t fee = stoull(*fee_string); - BOOST_REQUIRE(fee == 330050000); + BOOST_REQUIRE(fee == 237340000); cout << "bridged__estimate_fee: " << fee << endl; } BOOST_AUTO_TEST_CASE(bridged__estimate_tx_weight) @@ -942,6 +943,7 @@ BOOST_AUTO_TEST_CASE(bridged__estimate_tx_weight) root.put("n_outputs", "2"); root.put("extra_size", "0"); root.put("bulletproof", "true"); + root.put("clsag", "true"); // auto ret_string = serial_bridge::estimate_tx_weight(args_string_from_root(root)); stringstream ret_stream; @@ -956,7 +958,7 @@ BOOST_AUTO_TEST_CASE(bridged__estimate_tx_weight) BOOST_REQUIRE(weight_string != none); BOOST_REQUIRE((*weight_string).size() > 0); uint64_t weight = stoull(*weight_string); - BOOST_REQUIRE(weight == 2677); + BOOST_REQUIRE(weight == 1925); cout << "bridged__estimate_tx_weight: " << weight << endl; } BOOST_AUTO_TEST_CASE(bridged__estimate_rct_tx_size) @@ -969,6 +971,7 @@ BOOST_AUTO_TEST_CASE(bridged__estimate_rct_tx_size) root.put("n_outputs", "2"); root.put("extra_size", "0"); root.put("bulletproof", "true"); + root.put("clsag", "true"); // auto ret_string = serial_bridge::estimate_rct_tx_size(args_string_from_root(root)); stringstream ret_stream; @@ -983,7 +986,7 @@ BOOST_AUTO_TEST_CASE(bridged__estimate_rct_tx_size) BOOST_REQUIRE(size_string != none); BOOST_REQUIRE((*size_string).size() > 0); size_t size = stoul(*size_string); - BOOST_REQUIRE(size == 1848); + BOOST_REQUIRE(size == 1416); cout << "bridged__estimate_rct_tx_size: " << size << endl; } BOOST_AUTO_TEST_CASE(bridged__generate_key_image) From a1ad13b016072e67cab2d4f82d9295e016a55c63 Mon Sep 17 00:00:00 2001 From: j-berman Date: Wed, 9 Mar 2022 21:21:05 -0500 Subject: [PATCH 2/2] typos --- README.md | 2 +- src/monero_transfer_utils.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 206502f..e80a332 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ Useful for displaying an estimated fee – To obtain exact fees, see "Creating a * `n_outputs: UInt32String` * `extra_size: UInt32String` * `bulletproof: BoolString` - * `clsag: BooLString` + * `clsag: BoolString` * Returns: `retVal: UInt32String` diff --git a/src/monero_transfer_utils.cpp b/src/monero_transfer_utils.cpp index 7204d07..a86d7e8 100644 --- a/src/monero_transfer_utils.cpp +++ b/src/monero_transfer_utils.cpp @@ -276,7 +276,7 @@ void monero_transfer_utils::send_step1__prepare_params_for_get_decoys( uint64_t attempt_at_min_fee; if (passedIn_attemptAt_fee == none) { attempt_at_min_fee = estimate_fee(true/*use_per_byte_fee*/, true/*use_rct*/, 1/*est num inputs*/, fake_outs_count, 2, extra.size(), bulletproof, clsag, base_fee, fee_multiplier, fee_quantization_mask); - // use a minimum viabale estimate_fee() with 1 input. It would be better to under-shoot this estimate, and then need to use a higher fee from calculate_fee() because the estimate is too low, + // use a minimum viable estimate_fee() with 1 input. It would be better to under-shoot this estimate, and then need to use a higher fee from calculate_fee() because the estimate is too low, // versus the worse alternative of over-estimating here and getting stuck using too high of a fee that leads to fingerprinting } else { attempt_at_min_fee = *passedIn_attemptAt_fee;