Author

Topic: [XMR] Monero - A secure, private, untraceable cryptocurrency - page 765. (Read 4670673 times)

legendary
Activity: 2492
Merit: 1473
LEALANA Bitcoin Grim Reaper

Great stuff. I would suggest keeping track of your posts and maybe writing them up into one or more "code walkthroughs" that can go into the knowledge base on the web site (anyone can add to the web site using github).



Okay cool, will do. I never used gitub other than to view source or download it. Never to update or add commits etc.

I'm keeping notes on my end and may end up compiling them for a "code walkthrough". Hopefully it will help others if I ever finish.

legendary
Activity: 2968
Merit: 1198

Great stuff. I would suggest keeping track of your posts and maybe writing them up into one or more "code walkthroughs" that can go into the knowledge base on the web site (anyone can add to the web site using github).

legendary
Activity: 2492
Merit: 1473
LEALANA Bitcoin Grim Reaper
So I figured I would post about where I am at in the source code and give some perspective on what is going on and how complex it is (well to me it is):

The transfer RPC command used in simplewallet.cpp references the following function:

transfer_main function specified in simplewallet.cpp
**you can see my commenting for my own understanding of what's going on**
Code:
bool simple_wallet::transfer_main(bool new_algorithm, const std::vector &args_)
{
  if (!try_connect_to_daemon())
    return true;

  std::vector local_args = args_;

  size_t fake_outs_count;
  if(local_args.size() > 0) {
    if(!epee::string_tools::get_xtype_from_string(fake_outs_count, local_args[0]))
    {
      fake_outs_count = DEFAULT_MIX;
    }
    else
    {
      local_args.erase(local_args.begin());
    }
  }

  if(local_args.size() < 2) //parameter error checking
  {
     fail_msg_writer() << tr("wrong number of arguments");
     return true;
  }

  if(m_wallet->watch_only()) //view only wallet?
  {
     fail_msg_writer() << tr("This is a watch only wallet");
     return true;
  }

  std::vector extra; //used to store extra_nonce (random value?? or payment id?)
  bool payment_id_seen = false;
  if (1 == local_args.size() % 2) //if am using payment id argument (then amount of arguments is always odd)
  {
    std::string payment_id_str = local_args.back(); //get last argument payment_id as a STRING type
    local_args.pop_back(); //delete it from local_args

    crypto::hash payment_id; //of type POD_CLASS and has payment_id.DATA[32] member array
    bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
    if(r) //determine if payment_id is LONG (32 or 64 hex)
    {
      std::string extra_nonce; //of "blobdata" or string type
      set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); //payment id here can be any 64 char hex
      r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
    }
    else //or SHORT (8 or 16 hex)
    {
      crypto::hash8 payment_id8;
      r = tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8);
      if(r)
      {
        std::string extra_nonce;
        set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8); // "ENCRYPTED PAYMENT ID"???? <---- can be any 16char hex
        r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
      }
    }

    if(!r) // if payment_id is not 16 hex or 16 hex characters then it is an invalid payment id
    {
      fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character string: ") << payment_id_str;
      return true;
    }
    payment_id_seen = true;
  }

  vector dsts; //tx_destinations (dynamic sized array)
  for (size_t i = 0; i < local_args.size(); i += 2) //pairs of address and amounts (do all)
  {
    cryptonote::tx_destination_entry de; //structure to store 1) amount and  2) address
    bool has_payment_id;
    crypto::hash8 new_payment_id; //to hold 16 hex chars
    if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i]))   //if no payment id
    {
      // if treating as an address fails, try as url
      bool dnssec_ok = false;
      std::string url = local_args[i];

      // attempt to get address from dns query
      auto addresses_from_dns = tools::wallet2::addresses_from_url(url, dnssec_ok);

      // for now, move on only if one address found
      if (addresses_from_dns.size() == 1)
      {
        if (get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), addresses_from_dns[0]))
        {
          // if it was an address, prompt user for confirmation.
          // inform user of DNSSEC validation status as well.

          std::string dnssec_str;
          if (dnssec_ok)
          {
            dnssec_str = tr("DNSSEC validation passed");
          }
          else
          {
            dnssec_str = tr("WARNING: DNSSEC validation was unsuccessful, this address may not be correct!");
          }
          std::stringstream prompt;
          prompt << tr("For URL: ") << url
                 << ", " << dnssec_str << std::endl
                 << tr(" Monero Address = ") << addresses_from_dns[0]
                 << std::endl
                 << tr("Is this OK? (Y/n) ")
          ;

          // prompt the user for confirmation given the dns query and dnssec status
          std::string confirm_dns_ok = command_line::input_line(prompt.str());
          if (confirm_dns_ok != "Y" && confirm_dns_ok != "y" && confirm_dns_ok != "Yes" && confirm_dns_ok != "yes"
            && confirm_dns_ok != tr("yes") && confirm_dns_ok != tr("no"))
          {
            fail_msg_writer() << tr("You have cancelled the transfer request");
            return true;
          }
        }
        else
        {
          fail_msg_writer() << tr("Failed to get a Monero address from: ") << local_args[i];
          return true;
        }
      }
      else if (addresses_from_dns.size() > 1)
      {
        fail_msg_writer() << tr("Not yet supported: Multiple Monero addresses found for given URL: ") << url;
      }
      else
      {
        fail_msg_writer() << tr("Wrong address: ") << local_args[i];
        return true;
      }
    }

    if (has_payment_id) //if there is payment_id
    {
      if (payment_id_seen)
      {
        fail_msg_writer() << tr("A single transaction cannot use more than one payment id: ") << local_args[i];
        return true;
      }

      std::string extra_nonce;
      set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, new_payment_id);
      bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
      if(!r)
      {
        fail_msg_writer() << tr("Failed to set up payment id, though it was decoded correctly");
        return true;
      }
    }

    bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
    if(!ok || 0 == de.amount)
    {
      fail_msg_writer() << tr("amount is wrong: ") << local_args[i] << ' ' << local_args[i + 1] <<
        ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits::max());
      return true;
    }

    dsts.push_back(de); //add transaction to the queue/
  }

  try
  {
    // figure out what tx will be necessary
    std::vector ptx_vector;
    if (new_algorithm)
      ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra);
    else
      ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra);

    // if more than one tx necessary, prompt user to confirm
    if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1)
    {
        uint64_t total_fee = 0;
        for (size_t n = 0; n < ptx_vector.size(); ++n)
        {
          total_fee += ptx_vector[n].fee;
        }

        std::string prompt_str = (boost::format(tr("Your transaction needs to be split into %llu transactions.  "
          "This will result in a transaction fee being applied to each transaction, for a total fee of %s.  Is this okay?  (Y/Yes/N/No)")) %
          ((unsigned long long)ptx_vector.size()) % print_money(total_fee)).str();
        std::string accepted = command_line::input_line(prompt_str);
        if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes")
        {
          fail_msg_writer() << tr("Transaction cancelled.");

          // would like to return false, because no tx made, but everything else returns true
          // and I don't know what returning false might adversely affect.  *sigh*
          return true;
        }
    }

    // actually commit the transactions
    while (!ptx_vector.empty())
    {
      auto & ptx = ptx_vector.back();
      m_wallet->commit_tx(ptx);
      success_msg_writer(true) << tr("Money successfully sent, transaction ") << get_transaction_hash(ptx.tx);

      // if no exception, remove element from vector
      ptx_vector.pop_back();
    }
  }
  catch (const tools::error::daemon_busy&)
  {
    fail_msg_writer() << tr("daemon is busy. Please try later");
  }
  catch (const tools::error::no_connection_to_daemon&)
  {
    fail_msg_writer() << tr("no connection to daemon. Please, make sure daemon is running.");
  }
  catch (const tools::error::wallet_rpc_error& e)
  {
    LOG_ERROR("Unknown RPC error: " << e.to_string());
    fail_msg_writer() << tr("RPC error: ") << e.what();
  }
  catch (const tools::error::get_random_outs_error&)
  {
    fail_msg_writer() << tr("failed to get random outputs to mix");
  }
  catch (const tools::error::not_enough_money& e)
  {
    fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) %
      print_money(e.available()) %
      print_money(e.tx_amount() + e.fee())  %
      print_money(e.tx_amount()) %
      print_money(e.fee());
  }
  catch (const tools::error::not_enough_outs_to_mix& e)
  {
    auto writer = fail_msg_writer();
    writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":";
    for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs())
    {
      writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size();
    }
  }
  catch (const tools::error::tx_not_constructed&)
  {
    fail_msg_writer() << tr("transaction was not constructed");
  }
  catch (const tools::error::tx_rejected& e)
  {
    fail_msg_writer() << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
  }
  catch (const tools::error::tx_sum_overflow& e)
  {
    fail_msg_writer() << e.what();
  }
  catch (const tools::error::zero_destination&)
  {
    fail_msg_writer() << tr("one of destinations is zero");
  }
  catch (const tools::error::tx_too_big& e)
  {
    fail_msg_writer() << tr("Failed to find a suitable way to split transactions");
  }
  catch (const tools::error::transfer_error& e)
  {
    LOG_ERROR("unknown transfer error: " << e.to_string());
    fail_msg_writer() << tr("unknown transfer error: ") << e.what();
  }
  catch (const tools::error::wallet_internal_error& e)
  {
    LOG_ERROR("internal error: " << e.to_string());
    fail_msg_writer() << tr("internal error: ") << e.what();
  }
  catch (const std::exception& e)
  {
    LOG_ERROR("unexpected error: " << e.what());
    fail_msg_writer() << tr("unexpected error: ") << e.what();
  }
  catch (...)
  {
    LOG_ERROR("Unknown error");
    fail_msg_writer() << tr("unknown error");
  }

  return true;
}


I'm on the line that calls create_transactions

Code:
ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra);

Which calls the following code in wallet2.cpp:

Code:
std::vector wallet2::create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra)
{

  // failsafe split attempt counter
  size_t attempt_count = 0;

  for(attempt_count = 1; ;attempt_count++) //this runs and runs until it has exhausted all possibilities with the blockchain
  { //this is where when I ran mixin of 200 on testnet it would take a while
    size_t num_tx = 0.5 + pow(1.7,attempt_count-1); //

    auto split_values = split_amounts(dsts, num_tx);

    // Throw if split_amounts comes back with a vector of size different than it should
    if (split_values.size() != num_tx)
    {
      throw std::runtime_error("Splitting transactions returned a number of potential tx not equal to what was requested");
    }

    std::vector ptx_vector; //pending transaction
    try
    {
      // for each new destination vector (i.e. for each new tx)
      for (auto & dst_vector : split_values)
      {
        cryptonote::transaction tx; //tx
        pending_tx ptx; //pending tx

// loop until fee is met without increasing tx size to next KB boundary.
uint64_t needed_fee = 0;
do
{
transfer(dst_vector, fake_outs_count, unlock_time, needed_fee, extra, tx, ptx); //does a dust conversion as opposed to original transfer function that gets called anyways
auto txBlob = t_serializable_object_to_blob(ptx.tx);
uint64_t txSize = txBlob.size();
uint64_t numKB = txSize / 1024;
if (txSize % 1024)
{
numKB++;
}
needed_fee = numKB * FEE_PER_KB;
} while (ptx.fee < needed_fee);

        ptx_vector.push_back(ptx);

        // mark transfers to be used as "spent"
        BOOST_FOREACH(transfer_container::iterator it, ptx.selected_transfers)
          it->m_spent = true;
      }

      // if we made it this far, we've selected our transactions.  committing them will mark them spent,
      // so this is a failsafe in case they don't go through
      // unmark pending tx transfers as spent
      for (auto & ptx : ptx_vector)
      {
        // mark transfers to be used as not spent
        BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers)
          it2->m_spent = false;

      }

      // if we made it this far, we're OK to actually send the transactions
      return ptx_vector;

    }
    // only catch this here, other exceptions need to pass through to the calling function
    catch (const tools::error::tx_too_big& e)
    {

      // unmark pending tx transfers as spent
      for (auto & ptx : ptx_vector)
      {
        // mark transfers to be used as not spent
        BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers)
          it2->m_spent = false;

      }

      if (attempt_count >= MAX_SPLIT_ATTEMPTS)
      {
        throw;
      }
    }
    catch (...)
    {
      // in case of some other exception, make sure any tx in queue are marked unspent again

      // unmark pending tx transfers as spent
      for (auto & ptx : ptx_vector)
      {
        // mark transfers to be used as not spent
        BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers)
          it2->m_spent = false;

      }

      throw;
    }
  }
}


Within the create_transactions function I am on the line:

Code:
transfer(dst_vector, fake_outs_count, unlock_time, needed_fee, extra, tx, ptx);

Where another function called "transfer"(A) is called with 7 parameters is called repeatedly until the fee amount is met to satisfy the FEE_PER_KB * txsize  amount "needed_fee".

This transfer(A) function then calls another function named "transfer"(B) is called with 9 parameters specifying the dust threshold which is 0.01XMR called in wallet2.h

Code:
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), tx, ptx);

The source of transfer(B) function is:

Code:
template
  void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count,
    uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx)
  {
    using namespace cryptonote;
    // throw if attempting a transaction with no destinations
    THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);

    uint64_t needed_money = fee;

    // calculate total amount being sent to all destinations
    // throw if total amount overflows uint64_t
    BOOST_FOREACH(auto& dt, dsts) //copies all the contents from dsts to dt by reference temporarily for each interation of loop.
//BOOST_FOREACH(auto& , )
    {
      THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination);
      needed_money += dt.amount; //sum up each of the amounts of each address/amount pair
      THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_testnet);
    }

    // randomly select inputs for transaction
    // throw if requested send amount is greater than amount available to send
    std::list selected_transfers;
    uint64_t found_money = select_transfers(needed_money, 0 == fake_outputs_count, dust_policy.dust_threshold, selected_transfers); //get found money based on existing inputs (reg & dust) - get input indices also
    THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);

    typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
    typedef cryptonote::tx_source_entry::output_entry tx_output_entry;

    COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
    if(fake_outputs_count)
    {
      connect_to_daemon();
      THROW_WALLET_EXCEPTION_IF(!check_connection(), error::no_connection_to_daemon, "get_random_outs");
      uint64_t outs_count = fake_outputs_count + 1;
      std::vector amounts;
      BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
      {
        THROW_WALLET_EXCEPTION_IF(it->m_tx.vout.size() <= it->m_internal_output_index, error::wallet_internal_error,
          "m_internal_output_index = " + std::to_string(it->m_internal_output_index) +
          " is greater or equal to outputs count = " + std::to_string(it->m_tx.vout.size()));
        amounts.push_back(it->amount());
      }

      zframe_t *amounts_frame = zframe_new(&amounts[0], amounts.size() * sizeof(uint64_t));
      int rc = wap_client_random_outs(ipc_client, outs_count, &amounts_frame);

      uint64_t status = wap_client_status(ipc_client);
      THROW_WALLET_EXCEPTION_IF(status == IPC::STATUS_CORE_BUSY, error::daemon_busy, "getrandomouts");
      // TODO: Use a code to string mapping of errors
      THROW_WALLET_EXCEPTION_IF(status == IPC::STATUS_RANDOM_OUTS_FAILED, error::get_random_outs_error, "IPC::STATUS_RANDOM_OUTS_FAILED");
      THROW_WALLET_EXCEPTION_IF(status != IPC::STATUS_OK, error::get_random_outs_error, "!IPC:STATUS_OK");
  
      // Convert ZMQ response back into RPC response object.
      zframe_t *outputs_frame = wap_client_random_outputs(ipc_client);
      uint64_t frame_size = zframe_size(outputs_frame);
      char *frame_data = reinterpret_cast(zframe_data(outputs_frame));
      rapidjson::Document json;
      THROW_WALLET_EXCEPTION_IF(json.Parse(frame_data, frame_size).HasParseError(), error::get_random_outs_error, "Couldn't JSON parse random outputs.");
      for (rapidjson::SizeType i = 0; i < json["outputs"].Size(); i++) {
        COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount output;
        output.amount = json["outputs"][i]["amount"].GetInt64();
        for (rapidjson::SizeType j = 0; j < json["outputs"][i]["outs"].Size(); j++) {
          COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry entry;
          entry.global_amount_index = json["outputs"][i]["outs"][j]["global_amount_index"].GetInt64();
          std::string out_key(json["outputs"][i]["outs"][j]["out_key"].GetString(), json["outputs"][i]["outs"][j]["out_key"].GetStringLength());
          memcpy(entry.out_key.data, out_key.c_str(), 32);
          output.outs.push_back(entry);
        }
        daemon_resp.outs.push_back(output);
      }

      std::vector scanty_outs;
      BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs)
      {
        if (amount_outs.outs.size() < fake_outputs_count)
        {
          scanty_outs.push_back(amount_outs);
        }
      }
      THROW_WALLET_EXCEPTION_IF(!scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
    }

    //prepare inputs
    size_t i = 0;
    std::vector sources;
    BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
    {
      sources.resize(sources.size()+1);
      cryptonote::tx_source_entry& src = sources.back();
      transfer_details& td = *it;
      src.amount = td.amount();
      //paste mixin transaction
      if(daemon_resp.outs.size())
      {
        daemon_resp.outs[i].outs.sort([](const out_entry& a, const out_entry& b){return a.global_amount_index < b.global_amount_index;});
        BOOST_FOREACH(out_entry& daemon_oe, daemon_resp.outs[i].outs)
        {
          if(td.m_global_output_index == daemon_oe.global_amount_index)
            continue;
          tx_output_entry oe;
          oe.first = daemon_oe.global_amount_index;
          oe.second = daemon_oe.out_key;
          src.outputs.push_back(oe);
          if(src.outputs.size() >= fake_outputs_count)
            break;
        }
      }

      //paste real transaction to the random index
      auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a)
      {
        return a.first >= td.m_global_output_index;
      });
      //size_t real_index = src.outputs.size() ? (rand() % src.outputs.size() ):0;
      tx_output_entry real_oe;
      real_oe.first = td.m_global_output_index;
      real_oe.second = boost::get(td.m_tx.vout[td.m_internal_output_index].target).key;
      auto interted_it = src.outputs.insert(it_to_insert, real_oe);
      src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx);
      src.real_output = interted_it - src.outputs.begin();
      src.real_output_in_tx_index = td.m_internal_output_index;
      detail::print_source_entry(src);
      ++i;
    }

    cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
    if (needed_money < found_money)
    {
      change_dts.addr = m_account.get_keys().m_account_address;
      change_dts.amount = found_money - needed_money;
    }

    uint64_t dust = 0;
    std::vector splitted_dsts;
    destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust);
    THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < dust, error::wallet_internal_error, "invalid dust value: dust = " +
      std::to_string(dust) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold));
    if (0 != dust && !dust_policy.add_to_fee)
    {
      splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust));
    }

    crypto::secret_key tx_key;
    bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key);
    THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet);
    THROW_WALLET_EXCEPTION_IF(m_upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, m_upper_transaction_size_limit);

    std::string key_images;
    bool all_are_txin_to_key = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
    {
      CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false);
      key_images += boost::to_string(in.k_image) + " ";
      return true;
    });
    THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx);

    ptx.key_images = key_images;
    ptx.fee = fee;
    ptx.dust = dust;
    ptx.tx = tx;
    ptx.change_dts = change_dts;
    ptx.selected_transfers = selected_transfers;
    ptx.tx_key = tx_key;
  }


Within transfer(B) the following line is called with function select_transfers:

Code:
select_transfers(needed_money, 0 == fake_outputs_count, dust_policy.dust_threshold, selected_transfers);

This function is specified in wallet2.cpp.

What it does is:

Quote
//----------------------------------------------------------------------------------------------------
// Select random input sources for transaction.
// returns:
//    direct return: amount of money found
//    modified reference: selected_transfers, a list of iterators/indices of input sources

As you can see at this point there is a lot of drilling down into multiple function calls calling other functions.

select_transfers
Code:
uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list& selected_transfers)
{
  std::vector unused_transfers_indices;
  std::vector unused_dust_indices;

  // aggregate sources available for transfers (by storing the indices that are unspent) in OUR wallet
  // if dust needed, take dust from only one source (so require source has at least dust amount)
  for (size_t i = 0; i < m_transfers.size(); ++i) //m_transfers delared in wallet2.h and of type "transfer_container"  <---std::vector type
  {
    const transfer_details& td = m_transfers[i]; //"transfer_details" struct
    if (!td.m_spent && is_transfer_unlocked(td)) //has following members
    { //uint64_t m_block_height
      if (dust < td.amount()) //cryptonote::transaction m_tx
        unused_transfers_indices.push_back(i); //size_t m_internal_output_index
      else //uint64_t m_global_output_index
        unused_dust_indices.push_back(i); // bool m_spent;
    } //crypto::key_image m_key_image; //TODO: key_image stored twice :(
  } //uint64_t amount() const { return m_tx.vout[m_internal_output_index].amount; }

  bool select_one_dust = add_dust && !unused_dust_indices.empty();
  uint64_t found_money = 0;
  while (found_money < needed_money && (!unused_transfers_indices.empty() || !unused_dust_indices.empty())) //keep iterating through inputs until enough money has been found (or we run out of inputs to look through)
  {
    size_t idx;
    if (select_one_dust)
    {
      idx = pop_random_value(unused_dust_indices); //choose one dust input amount by index
      select_one_dust = false;
    }
    else
    {
      idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices); //get index from non dust inputs. If no more non dust then select index from dust inputs to use.
    }

    transfer_container::iterator it = m_transfers.begin() + idx;
    selected_transfers.push_back(it);
    found_money += it->amount(); //keep a running SUM of all the found money from inputs
  }

  return found_money;
}

It finds random inputs in the wallet you are running simplewallet with and makes sure you have enough input amounts + dust to at least equal fee + amount to transfer.


Now at this point I'm going to continue to read the first function at the top and keep going from there, where I left off after the function call create_transactions

I'm finding it sort of therapeutic to read source code learn new keywords and operators etc in C++ that I never learned in my schooling in computer science.

There is a lot going on in just this one RPC command "transfer". There is a "transfer_new" which I have not delved into much yet.

I'll post more in the future once I have better understanding of the code or just want to update on where my reading and commenting for myself is at.

Trust me there is much more going on in other places of the code on a bit-wise level of shifting bits LEFT and RIGHT etc in the portion that creates your secret/view keys etc when you create an ACCOUNT in simple wallet. <---- very complex math

All for now.. Grin
pa
hero member
Activity: 528
Merit: 501
Trip report on running the windows 0.9 beta for the past week or two.  Other than the known issue of needing to type exit 2 separate times in order to exit it has been running smoothly.  It has been using <40MB memory Smiley

I've been on the latest Windows beta for ages now, have done quite a few transactions, no issues at all here.
On exit, the daemon looks to have a wait right after stopping some network function. I don't ever need to type exit 2 times. I just type exit once, then after a few seconds, I just hit enter again.

Yes that worked, Thanks Smiley

Is anyone able to reproduce this problem reliably, and able to build an arbitrary branch of monero, and willing to test and report any patch I make to try and fix this problem ?


I think (on OS X), the "No Exit" bug occurs mainly when the runtime is short, e.g. < 5 minutes. I haven't done exhaustive experiments but I rarely or never see the bug when I keep the daemon running for a few minutes, but I've seen it about 50% of the time when I try to exit soon after getting the "Use help command to see the list of available commands" message.

Oddly, "exit" in these cases just leads to a "Stop signal sent" message, whereas ctrl-C actually initiates the exit sequence, which then hangs on the "Deinitializing cryptonote_protocol" step. Typing "exit" there gets me a "Segmentation fault: 11" message.


legendary
Activity: 2492
Merit: 1473
LEALANA Bitcoin Grim Reaper
Trip report on running the windows 0.9 beta for the past week or two.  Other than the known issue of needing to type exit 2 separate times in order to exit it has been running smoothly.  It has been using <40MB memory Smiley

I've been on the latest Windows beta for ages now, have done quite a few transactions, no issues at all here.
On exit, the daemon looks to have a wait right after stopping some network function. I don't ever need to type exit 2 times. I just type exit once, then after a few seconds, I just hit enter again.

Yes that worked, Thanks Smiley

Is anyone able to reproduce this problem reliably, and able to build an arbitrary branch of monero, and willing to test and report any patch I make to try and fix this problem ?


It might be windows only, and it might be related to that specific beta build (which was months ago at this point). for me, recent head exits cleanly in ubuntu. For the sake of argument, re: "able to build an arbitrary branch of monero", would you want the beta tester to compile in for windows?

For me it happened on Ubuntu 14.04 I believe it was when I was using testnet while sending a transaction with a huge mixin and it had to be split up into 5 separate transactions.

I'll have to double check though but it happened more than once to me.

Edit: On second though I believe on exit the issue did happen to me where the daemon just hung before deinitializing.

I'll have to try again to see if it happens consistently.
legendary
Activity: 2492
Merit: 1473
LEALANA Bitcoin Grim Reaper
Trip report on running the windows 0.9 beta for the past week or two.  Other than the known issue of needing to type exit 2 separate times in order to exit it has been running smoothly.  It has been using <40MB memory Smiley

I've been on the latest Windows beta for ages now, have done quite a few transactions, no issues at all here.
On exit, the daemon looks to have a wait right after stopping some network function. I don't ever need to type exit 2 times. I just type exit once, then after a few seconds, I just hit enter again.

This ^ is the same for me. Hitting enter again sometimes does the trick after running certain commands.
legendary
Activity: 2492
Merit: 1473
LEALANA Bitcoin Grim Reaper
Some questions, with upfront apologies for not searching the thread for answers:

Re the current blocksize debate now creating a duststorm in the bitcoin world - is there a similar blocksize controversy in monero's future?  

Oversimplifying one aspect of the debate - centralization - if the next 3 to 5 years see a destruction of the decentralization of bitcoin, is monero in a position to observe, learn, and survive, or will monero be swept away by the same forces of centralization (in the event monero becomes the "alpha coin" after the demise of bitcoin)?

tl;dr    If centralization destroys bitcoin, will centralization inevitably destroy all cryptocurrency?



also, moneromoo has come up with a pool resistance approach that passed the smooth filter, something none of my ideas have ever done. no idea how it will do in the wild.

It's more of a rough concept, no specific design, no code, etc. We'll see how it looks once some details are worked out, but there is potential it could work.

Is there any link to the rough concept online? If so, Please link us. Thanks
legendary
Activity: 2268
Merit: 1141
I can't believe that changing the emission curve is being discussed in page 800+ of this thread. If the emission curve was such a problem it would have been fixed immediately. XMR's emission curve is what it is so enough already with the emission curve please.

Enough already

??  Whats this year old post have to do with anything?

I believe it has to do with the emission curve, not entirely sure though. Anyway it seems to be enough already.

I think he meant why this particular post was dug up? Makes no sense to me as well. Anyway, let's take up where we left off.
hero member
Activity: 966
Merit: 1003
I can't believe that changing the emission curve is being discussed in page 800+ of this thread. If the emission curve was such a problem it would have been fixed immediately. XMR's emission curve is what it is so enough already with the emission curve please.

Enough already

??  Whats this year old post have to do with anything?

I believe it has to do with the emission curve, not entirely sure though. Anyway it seems to be enough already.
legendary
Activity: 2968
Merit: 1198
My first report on 0.9 beta release
+ Database size after sync-ed: data.mdb 9,437,187 KB (9.4 GB) (block 797721)

Hey, strange, I updated Monero today and my database is only 5.079.778 KB !?? (Windows 10)
Version 0.8.8.6
Why such differences ?

The new database doesn't store the data all that compactly. Some amount of extra space being used is reasonable to improve performance but the 9+ GB does seem a bit excessive and is something we plan to look at in the future. BTW the 5 GB isn't that efficient either. If someone has an export file they can report on the actual size of the blockchain. It's smaller than both of those.

legendary
Activity: 1260
Merit: 1008
oh that and ure on the old non database format
legendary
Activity: 1260
Merit: 1008
My first report on 0.9 beta release
+ Database size after sync-ed: data.mdb 9,437,187 KB (9.4 GB) (block 797721)

Hey, strange, I updated Monero today and my database is only 5.079.778 KB !?? (Windows 10)
Version 0.8.8.6
Why such differences ?

windows apparently has a fun time with sparse file formats, or at least thats what fluffy said.

https://en.wikipedia.org/wiki/Sparse_file

basically, the file is mostly empty. if u compressed it with zip or whatever, you'd see a file size reminiscent of the actual data, bc no compression algo is gonna do wonders with crypto data, as its mostly psuedo-random nonsense with little to no patterns
sr. member
Activity: 263
Merit: 250
My first report on 0.9 beta release
+ Database size after sync-ed: data.mdb 9,437,187 KB (9.4 GB) (block 797721)

Hey, strange, I updated Monero today and my database is only 5.079.778 KB !?? (Windows 10)
Version 0.8.8.6
Why such differences ?
legendary
Activity: 1276
Merit: 1001
For the sake of argument, re: "able to build an arbitrary branch of monero", would you want the beta tester to compile in for windows?

If the tester can reliably reproduce it for windows, yes.
Though if ends up in some windows code (as opposed to normal code that just happens to break on Windows), I guess I'll have to leave it to someone else.
legendary
Activity: 1260
Merit: 1008
Trip report on running the windows 0.9 beta for the past week or two.  Other than the known issue of needing to type exit 2 separate times in order to exit it has been running smoothly.  It has been using <40MB memory Smiley

I've been on the latest Windows beta for ages now, have done quite a few transactions, no issues at all here.
On exit, the daemon looks to have a wait right after stopping some network function. I don't ever need to type exit 2 times. I just type exit once, then after a few seconds, I just hit enter again.

Yes that worked, Thanks Smiley

Is anyone able to reproduce this problem reliably, and able to build an arbitrary branch of monero, and willing to test and report any patch I make to try and fix this problem ?


It might be windows only, and it might be related to that specific beta build (which was months ago at this point). for me, recent head exits cleanly in ubuntu. For the sake of argument, re: "able to build an arbitrary branch of monero", would you want the beta tester to compile in for windows?
legendary
Activity: 1260
Merit: 1008
Anyone running any of the GUIs with the latest non official DB version of Monero?

I did recently run jwinterms wallet to a remote daemon (in my home network) that was running the latest git build.
legendary
Activity: 1456
Merit: 1000
Anyone running any of the GUIs with the latest non official DB version of Monero?
legendary
Activity: 1276
Merit: 1001
Trip report on running the windows 0.9 beta for the past week or two.  Other than the known issue of needing to type exit 2 separate times in order to exit it has been running smoothly.  It has been using <40MB memory Smiley

I've been on the latest Windows beta for ages now, have done quite a few transactions, no issues at all here.
On exit, the daemon looks to have a wait right after stopping some network function. I don't ever need to type exit 2 times. I just type exit once, then after a few seconds, I just hit enter again.

Yes that worked, Thanks Smiley

Is anyone able to reproduce this problem reliably, and able to build an arbitrary branch of monero, and willing to test and report any patch I make to try and fix this problem ?
hero member
Activity: 532
Merit: 500
Did you set the bandwith limit? I think the default is 1 mbps still.
legendary
Activity: 2268
Merit: 1141
My first report on 0.9 beta release

+ Windows 7
+ Sync from start to block 797721: take more than a day
+ Database size after sync-ed: data.mdb 9,437,187 KB (9.4 GB) (block 797721)
+ Memory:

   Private Working Set): 21,277 KB (21 MB)
   Commit Size: 109,880 KB (109 MB)
   Working Set: 38,040 KB (38 MB)

+ Startup time: About 2 seconds
+ Exit time: About 3-5 seconds

Huge improvements over 0.8.8 release!

Nice report! The bolded is probably due to a slow connection or a HDD. It takes around 45-60 min to fully sync from scratch on an SSD and it took me around 4 hours on a HDD.
Jump to: