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.
|
|
|
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**bool simple_wallet::transfer_main(bool new_algorithm, const std::vector<std::string> &args_) { if (!try_connect_to_daemon()) return true;
std::vector<std::string> 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<uint8_t> 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<cryptonote::tx_destination_entry> 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<uint64_t>::max()); return true; }
dsts.push_back(de); //add transaction to the queue/ }
try { // figure out what tx will be necessary std::vector<tools::wallet2::pending_tx> 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_transactionsptx_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: std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> 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<pending_tx> 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: 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 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: template<typename T> void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& 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& <variable>, <sequence>) { 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<transfer_container::iterator> 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<uint64_t> 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<char*>(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<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> 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<cryptonote::tx_source_entry> 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<txout_to_key>(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<cryptonote::tx_destination_entry> 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: 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: //---------------------------------------------------------------------------------------------------- // 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 uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers) { std::vector<size_t> unused_transfers_indices; std::vector<size_t> 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<transfer_details> 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_transactionsI'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..
|
|
|
... How many people claimed this that you can quote?
100? 200? 300?
Please enlighten us all on how many you have actually heard from claiming this.
Again, read through the start of the thread instead of taking the word of random fudders as gospel, there's about a dozen posts from established miners offering 10k and 20k batches for sale. Do your own research ffs. No. You made the claim, now back it up. You pointed to the IP list claiming that many miners were there at the start, that claim gets refuted by ip address association. Now you responded making claims contrary to what some of us see. No, you made all kinds of false claims and I'm refuting them. Here's someone who was there: https://bitcointalk.org/index.php?topic=421615.msg12691335#msg12691335EDIT: Quoting in case clicking a link's too much trouble for you: clearly a mistake... With all the damning evidence released clearly showing the instamine was obviously intentional........ "evidence"? I'll try to reply to a troll I was there during the "instamine", go check the first pages of this thread and you will see me complaining and discussing. Evan updated the code many times during the first hours/days because various mistakes. I had some talks in IRC with him during the first days/weeks, and my conclusion was that the instamine happened because he just wasn't very familiarized with Bitcoin codebase and he didn't test his coin properly before launch, plus, at that time most coins were launched without a proper difficulty adjustment algorithm (Kimoto's Gravity Well was fresh new at that time and most coins didn't include it at launch). I also saw his nickname mining in pools, he didn't even ranking top 10 of the miners (and pools had most of network's hashrate), at that time people didn't hide their nicknames in pools and you were used to see always the same names. Moreover, if you spend some minutes analyzing the blockchain and you follow the first 1-10 mined blocks (those that are clearly mined by the dev) you will see that eventually they all go to the same addresses, with many other blocks and coins coming from pool-mining, and finally these after weeks don't account for more than 80k XCoins (about 2BTC at the time). I guess that's why he tried to buy some more, and he made it publicly (of course people like you would had thought he was hyping it to then dump his coins at higher price). https://bitcointalk.org/index.php?topic=421615.msg4961359#msg4961359But the most important, the instamine didn't matter, if anything, it helped with the distribution, and the reason is because during the first weeks of life of XCoin you could buy 100k XCoin for just 2.5BTC - 5BTC, so everyone had his chance for weeks to decide to risk and buy or just sell (I myself sold more than 50k XCoin for less than 2BTC, and decided to buy some back later more expensive): https://bitcointalk.org/index.php?topic=421615.msg4889177#msg4889177https://bitcointalk.org/index.php?topic=421615.msg4872871#msg4872871https://bitcointalk.org/index.php?topic=421615.msg4867363#msg4867363Next time you talk about the instamine, understand that those of us who don't care about it is because we understand what happened (can't say the same about you or others just repeating the same over and over without proper knowledge or analysis). We judge XCoin-Darkcoin-DASH (and Evan) for 20 months of upgrades, delivering promises and innovation, and we invest in it because we know it will continue delivering. Is that it? Oh and by the way it wasn't me who made the claim that "there was hundreds of miners"....it was your fearful leader Evan. So who needs to provide proof? I think Evan does, not me.
|
|
|
Fat Tay Choon went to the Mining Academy in Brazil, east of Satoshi's yurt, where Gavin was kidnapped by the CIA's goons and forced to pretend fucking an anonymous decentralized biscuit—better than all the fish in the Pacific Ocean—but also to defray leeches intelligently with ECDSA fighting qubits for 16.8 dree12, or Phinnaeus must fling toilets towards psy‐ops, without potato smoothies mixed with fried chicken wings from BitMunchies.com, urbanchickennj.com, and Popeye's Bitcoin wallet, which deleted Satoshi's premine ability to cheer very victoriously, none like Butterfly Labs better enabled, but also Pirate crashing AIR applications without the express use of interest-free scams, conspiring with fraudulent sockpuppets and PPTs and..., you troll-herding piece of Shiitake mushroom, go lick Goat's horns until Theymos admits to having a quite erotic fetish involving honey badgers wearing thongs composed of soggy burlap waffles dangling from cosmic linoleum-based iphones running quantum chips explodes spewing deadly acid! b!z screamed out "Light is bright like...like... stars." When Markjamrobin opens the isolated window, he sees three pigs together in bed. Kouye and myself laugh when chinese food falls the impact kills Obama Bin ladin whoever thinks he may be terrorist, is correct but hates the bitcoin logo. Earth has snakes. Currently, the other species have decimated to tiny groups called "marko solo" whatever time it all comes and ends? However, Bitcoin's acidity level dipped causing catastrophic double-spends!
Meanwhile, AntiOps was confused by the awkward change to his penis melting uncontrollably. Vanilla Ice perfume spritzed onto cheese and greasy slime covered with babies boiled in a smelly old heatsink. But it tasted like shit therefore it poisoned his blood although he did survive. Reproductive organisms attacked the internal testicle which caused terrible congestion somehow. Evolution then terminated the smelly old business thank the inability of AntiOps to lock Satoshi's thread. In a transactional forum there was a debate about hacking unprotected accounts, however the debate shortly ended.
Phinnaeus Gage, king pluto, duke of the people. Returned one of his loans that he fraudulently claimed without declaring intentionally. Although this was bullshit. Earth was hit by a meteor which cause catastrophic events which cause people to cause mass destruction by proxy voting it was documented recently on the news that oranges are disguised anti-gravity pockets which have giant bears attacked Zeus because bitcoin accidentally crashed to Mars which created spaceships and aliens who pretended being humans wearing hats on their toes.
Altcoin suck on apples and oranges too. Megacoin is the most shit sucker of apples and melons ever. Most people love to troll others. Evolution is a slow process which created forks. It is beneficial to wash your feet because it distributes bacteria and oil, notwithstanding the beneficial attributes which are how chocolate arouses some of the miners brains. Today was an abysmal event which caused many abnormal but not smart bitcoiners because many of them are cute animals who were insane because of excessive oreo consumption. One watermelon is not love how people try me explotation Maybe Heisenberg Breaking bad control guy director or masturbation my time vampire drinks urine not lemon tek and water supernatural.
LEALANA is fat looking because pizza is sour with pickles which are sexy and never rot. So many people eat pizza it's unbelievable. The news said that pizza is bought mainly with anchovies which results in big wet weather which had massive gusts of wind with pouring milk down on everyones throat because it feels great! Although honey is very sweet taste it makes when it is served hot it melts softly but slowly. The universe is populated with many planets which were destroyed by pirateat40. Cyborgs then warped to the zoo and ate mushroom with a aerospace technician. Bitcoin has used a lot resources from peoples although people smell like melons.
Ipods suck. Androids rule. Altcoins also suck peanuts. Bitcoin is the greatest idea that has ever been created by man although litecoin sucks? Once upon a time Gandalf went to wal-mart to dry her hair. Minecraft is the best game in universe because chickens cluck. 231134421 is one crazy big ass monkey. What is with people posting replies still. Terraria is a crazy game which requires extreme concentration. This can result in health cubes; Parentheses are a pain in the brain. This noodle is disgusting. Although spaceships cry waterfalls they are magical little elves. Golden towns is very annoying and smell like bacon. Celebrities are awesome and smart. But, evolution taught us that butterflys are ugly.
Vitamin D is important to scam Taras and raise taxes which would cause the world to go crazy but not insane. Obama is the president now. Alot of gamers will illustrate sony that nintendo is leading the infiltration of Iran. Microsoft Windows was salivating pedophiles of the coastal farts. Yet the banana shrank. What was doge poo doing under the bridge with bridge cleaner? He was just he's aren't because something something different like seems incorrect, because we fucked. Yet prunes prunes are very bad lad's yet unknown to fuckers SWEARING. Banana monkey is not virgin-horse. Corn.
This disappoints satan more than satoshi because he ate hydrochloric pools and he fucked whores who are sick shemales shemales shemales BANGCOCK! God smited non-believers with dicks on a stick. They shat together sitting upside-down flicking birdies. Baezl'bub slept with Hitler inside a bomb ticking furiously and hodling. That was awesome. Bitmit made belt so that walruses can shit on his dick and eat mushroom full of wonderful shit, he HODL'd BTCs and Dogecoin with a succubus sperm from first blowjob stories.
Nefarious words spoken shit at bitcointalk and destroyed uranus with a big-ass Spaceship mouth that eats goats flying shuttle that revolves expressly and quietly to hell. Gamma flux destroyed Litecoin with a barracks producing Atreides shit and Kadafi. Same Binladen puppet goxed clients sucking lollipops shaped like mixed frapuccino lids. Goku start this fight prematurely in Odessa Klondike's yard. Winter is not shitty. Gooches. Seven. Humanity sold pubes to Zeus. Nevertheless, Cinnamon was crying. Millennium breakdown caused diversification methheads cardinally. Hyper-inflation, epidemics with marshmallows made by government chodes and yeah. The End. No. Yes. Lies. Stop. Can. Do aliens have any bitcoins? No. Instead, PPC acts quickly like FTL shit, riffraff toys.
Miracles happen like cannibals spitting sinew and elephants which innocent love and shit has never fucked up! Dank has killed bysexuals... wait, when did Karpeles said/say McDonald's sucks? Colonel Tom sex-machine The 3.14159265358th must fook anything that goes into a section. Beaware of spellcheckers. Fantômas portuguese are sobriquet of Fernão who called them Coads-nigs! They say we are azoth, biblical tittynopes who can't mine the janiceps'. He biblically took Rosenzweig and ended this game. And then wanked, wanked clitoris next door. This was done. Moreover, crack was rapidly dephosphorylated due to complications anhidrotically, metaphorically whores go mooooooooo and ahhhhhhhhhhhhh while jon snow watch has ended this thread for good.
Not... Actually, maybe futuristically, Vod (MIA) sailing CASASCIUS up Padma Lakshmi's waxed butt and... Nevermind, but acknowledging that Gavin held security. This marks, categorically, that will create scientific controvertist of global heliolatry problems indistinguishably noticeable filipino heritage, unbeknownst to Slenderman XT phenomena. GLEB sucked smoothie's brains using juicy zombies, dicks, Popsicles, and alien vaginas to rotten flesh of Vod. Meanwhile, giant marsupials are having suicidal sex appeal for four tentacles, watching child whoopee. Therefore, vegetables are unpretentiously super[...]docious. Fruits are rotten potatoes, avouchment vouched x10 malware because aliens kidnapped JarJar, mercilessly LeFodorliar and Gleb Gamow lived days along seashore, Theymos abused his Authoritah by forcing a purple pill To Fly! Serendipitously, awsome! Then I started UFOing on their ass, savagely. But, it is impeccable to realize I farted psychedelic asparagus smoothies. However, Mexico is shit and... Rephrase that, corporations syria declared terrorists irreproachable because malevolence misappropriates monetary suffrage suggesting termination.
Meanwhile, yogurt spill has begun to fall onto houses and cars, hawkishly attempting to grab two crayons, inserting phallic Popsicles® into Theymos' abysm until... POOP! The excruciating pain took aeons to appreciate plethoric folliculitis silvestris poop generator. Why nidificate the indigenous spirit called "erection"? Prepossessingly, pneumonoultramicroscopicsilicovolcanoconiosis a discomfortable endoplasmic tumescent pineapple tree branch rectally QuickSeller escrow. Involution, presumptuously titin pop up inconsiderately - Tuesday - when pokemon (Pokémon)'s Pikachu flashbacked borders dementia caused horrendous pain inside Agumon's PocketPussy™.
Daft Punk punked Dank with pussy heavy hookah shot whilst levitating abroad oceans blue that fadedly waved the unseen quote yet cited. Unjust superexcrescences excuses me because of Neotox produced such force by Poseidon's Trident of Taured. Now, albeit-albeit DARKCOIN-SCAMCOIN but tried to interlock coins out of your anal cavity filled lordly exponentially with bold pumpkins wiggling back to school days yesterday morning. Onomatopoeias ate language. Rigveda inside coupons collectively jumped over the "Core Mission". Pussies annihilate doge.
Pythons and anacondas don't squirt unless you got into buns coin phlegm on their tongues. Why did GLEB touch my vault extravagantly? I galumphed after midnight parade on my horse galloping in reverse to realize "holey-moley". Forgotten equines maybe because MONERO promotions failed for several days made before ends of christmas so that it won't morbidly end happily at all. Overlord espials all within the safehouse CRACK and maths are increasingly hard to ejaculate onto pomegranates with penises flying about. Suddenly, Nikko realised, "SHIT! ...Pneumonoultramicroscopicsilicovolcanoconiosis, AGAIN!"
We shall never, NEVER go back beepbopping again. Then afterwards, Zelda found prophylactics transforming Macarena calisthenics to defeat her Herculean strenght - strength mispelled porpoisely - with Who (Doctor) movie scaring the fuck out of Casper. Time Lord fag get net work for Nicholas Tesla who's balls bounce before he collapsed after scratch the boobs of Vod. Vod never realized that was something amiss with quikseller of bitcointalk site escrow because he penetrated to the secret vault of stat and doubled the the bitcoins of the prison where Nakamoto lives imprisoned sans serif comics. Polymorphism, exhibitionism? No! NO! Exterminate! what the hell is happaning? Why did Satoshi die? It was because he farted on Lady "Gaga" Godiva.
Junior Samples make a wonder filled with excitement: Call Saul (BR549). Breaking Bad epitomizes the entirety of the methamphetamine movement. Alexithymia is putrid like smelly whit of publicity stunt whoopie such fail in mining field lockers that hentai sites gangbang with Hatsune Miku tentacles. The feelings I encountered when I meet the president, Millard Homomorphicity IV, I eyed him quizzically. Once Upon a Midnight afternoon when Gonzalez unwillingly took the rulebook down to Alabama and shat shit on the NASCAR while ca333 aka Bubba Kaninski filmed awesome rims.
Smoothie once lethargically stroked Phinnaeus Gage Vod where buffalo barrage claims cowpatties slapped with Limburger [poison] cheese. Poteepopoppooh kicked Kack in Walnut's park. CHOON tunes fat cat
|
|
|
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 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 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.
|
|
|
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 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.
|
|
|
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
|
|
|
Lots of shadiness surrounding Mr. Evan Duffield.
Yes he must be the shadiest of them all to justify that much energy being spent on him. And 99% of the people spending that energy are the coattail riders with little brother syndrome from one specific altcoin trying to control everything going on in the scene that doesn't conform to their socialist "fair launch" ideology. Yes we believe in different things. Our realities are very different. Well I'm not against instamining coins or premining them. <---- Personally I would never buy these. But if you are going to call it a feature then own up to it in every way possible and stop dodging the topic like Mr. Duff has done.
|
|
|
Because I am in it for the long term, I hope that when/if I one day spend my "eta" that I will do it directly. I fully expect that I will never 'sell' up to 50% of the Monero I acquire in these early stages. I actually like a modified form of Risto's plan, where every time the price goes up 10x you sell/trade 10% to increase the available supply and upgrade the quality of your life a little bit.
I think it's optimal to sell a bit more, such as 1/3 of the remaining after every 10x (although you can skip the first one, like I did with Bitcoin). Price hits $40: I sell 10% of what I acquired at under $1. Perhaps I buy a new car, and a tv finally. Price hits $400: I sell 10% and buy a house. $4000 Retire from my job and go full time Monero promotion, consulting, activist. Sell 10% for travel and living expenses over the next several years. $40,000: Sell 10%. Start a video game company (dream of my youth). With the exception of buying a TV (I don't need), I have done all this What's next on your list? Charity? Charity is not a potent way for changing the world. Perhaps going to prison and in the process becoming a global human rights leader could be the next step. I guess it depends on how you see the word Charity. Many human rights leaders donate their time and money to specific causes. There are many in the broken world we live in where privacy is no longer a right but just a word. XMR hopefully can help with this.
|
|
|
Darkcoin (Dash) is still in active development, it has many wealthy holders. It will not die any time soon.
Just because you are "developing" something does not make it worth while to be vested into it. Some people are great developers and some aren't I am guessing evan aint that great of a developer for: 1. He sent an email on the bitcoin-dev mailing list in November 2013 asking to pay for c++ coders to help him with his for-profit venture. He was laughed out of that email thread. 2. After spending many months using the masternode system he all of a sudden has stated publicly that he wants to get away from the masternode system. Sounds like bad development to me. It is development but if I slap together a piece of code that is essentially broken on its main purpose (privacy) what's the point? Yes one could argue that he was "developing" but it doesn't mean he was developing something worth spending time on for the longer term. Let's call it "DEVELOPMENT THEATRE" which implies ==> "PRIVACY THEATRE"
|
|
|
Here's his post about how the DASH team have as much DASH TRASH for sale as you could possibly want OTC:
I believe this is a service for projects funded by the blockchain i.e. projects get funding directly from the blockchain in DASH coins, and instead of them dumping the coins on an exchange to be able to pay the bills the team is helping out trying to organize OTC trades. Adams point was why did eduffield need to buy on an exchange and not OTC from the "team"...... Maybe he likes to trade? Maybe the OTC price was higher and he wanted to catch dumps. Maybe the OTC was reserved mainly for people who don't trust exchanges and don't want to use them. Maybe he didn't know the future that 2 days later there would be an OTC opportunity. Problem with that theory is that trading with cryptsy you have to pay large fees. Not sure when they started their 0.5% withdrawal fee. I'm also not sure if it was during or after or before they started 0% trading fees. The whole point is why go through the risk of sending your money to a 3rd party when you can hand your money over to someone you know and trust and get more dash per $. Makes no sense.
|
|
|
Much of the double talk I would like to hear Evan address as he is a public figure in the DASh community.
He said he would take responsibility for the instamine but when I asked him to take responsibility via posting that "DASH was instamined" on their main forum front page and the main page of their thread he has yet to do so.
Lots of shadiness surrounding Mr. Evan Duffield.
|
|
|
Because I am in it for the long term, I hope that when/if I one day spend my "eta" that I will do it directly. I fully expect that I will never 'sell' up to 50% of the Monero I acquire in these early stages. I actually like a modified form of Risto's plan, where every time the price goes up 10x you sell/trade 10% to increase the available supply and upgrade the quality of your life a little bit.
I think it's optimal to sell a bit more, such as 1/3 of the remaining after every 10x (although you can skip the first one, like I did with Bitcoin). Price hits $40: I sell 10% of what I acquired at under $1. Perhaps I buy a new car, and a tv finally. Price hits $400: I sell 10% and buy a house. $4000 Retire from my job and go full time Monero promotion, consulting, activist. Sell 10% for travel and living expenses over the next several years. $40,000: Sell 10%. Start a video game company (dream of my youth). With the exception of buying a TV (I don't need), I have done all this What's next on your list? Charity?
|
|
|
Funny you say that, Monero has not been around for 2 years. I think you stopped by for a quick afternoon Shill.
A cursory glance at his history shows a multi year agenda to pump bitshares and attack Monero... Unfortunately for him, math is not an opinion. Now only if you could shoot from the hip with a AK-47 and change the answer to a math problem...then he would be on to something. Nice short term bounce in the XMR price. Hoping it dips a bit.
|
|
|
rabble rabble unfair distribution rabble rabble
So you are one of the "I missed the boat so therefore I hate it" types- Gotchya. My bad, it seems Monero has pivoted since I last researched the project. I haven't been around much the past couple years. Perhaps you should do your research before shooting from the hip.
|
|
|
If you have an opinion on the matter, we just had a topic on Reddit discussing what to eventually call Monero atomic units on Reddit. (Yes, it's a conversation we've had before, and will have again). My favorite is a combination of the most popular suggestions, a millionth of a Monero being called a nero, and a millionth of a nero being called an eta. Check out the topic if you like: https://www.reddit.com/r/Monero/comments/3q21yx/its_time_to_argue_about_what_atomic_units_of/I like nero, but am not sold on eta yet. Instead of eta call it MO. lol j/k
|
|
|
0.28BTC
current high bid AUCTION ENDS TOMORROW AT A RANDOM TIME.
|
|
|
... How many people claimed this that you can quote?
100? 200? 300?
Please enlighten us all on how many you have actually heard from claiming this.
Again, read through the start of the thread instead of taking the word of random fudders as gospel, there's about a dozen posts from established miners offering 10k and 20k batches for sale. Do your own research ffs. No. You made the claim, now back it up. You pointed to the IP list claiming that many miners were there at the start, that claim gets refuted by ip address association. Now you responded making claims contrary to what some of us see.
|
|
|
Miners jump on coins at launch because of the low difficulty and those services give the best bang for your buck with CPU mining, why would Dash be any different? Because DASH didn´t work, there was no way to "jump on it" in the beginning. period. AWS and Azure instances are expensive, there is no way someone wastes thousands of dollars for a coin which is just a plain btc copy (initial announcement). You've not answered this one yet: ... Maybe you couldn't compile it but that doesn't mean others couldn't, did you fix it yourself or wait for a download? ...
Its fairly obvious many folks could get it to run so I've no idea why you couldn't get it to work, AES maybe? That is a pretty big assumption that HUNDREDS of people were compiling the source at launch. Most people just download binaries and start mining.
|
|
|
|