void splitTx(CryptoNote::WalletGreen &wallet, CryptoNote::TransactionParameters p) { std::cout << "Wallet optimization failed, transactions are still too large " << "to send in one chunk, splitting into multiple chunks." << std::endl << "This may take a long time as portions of your " << "balance get locked whilst sending a transaction." << std::endl << "It may also slightly raise the fee you have " << "to pay, and hence reduce the total amount you can send if " << "your balance cannot cover it." << std::endl; if (!confirm("Is this OK?")) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; return; } CryptoNote::TransactionParameters restoreInitialTx = p; uint64_t maxSize = wallet.getMaxTxSize(); size_t txSize = wallet.getTxSize(p); uint64_t minFee = CryptoNote::parameters::MINIMUM_FEE; for (int numTxMultiplier = 2; ; numTxMultiplier++) { p = restoreInitialTx; int numTransactions = int(numTxMultiplier * (std::ceil(double(txSize) / double(maxSize)))); uint64_t feePerTx = std::max (p.fee / numTransactions, minFee); uint64_t totalFee = feePerTx * numTransactions; uint64_t totalCost = p.destinations[0].amount + totalFee; if (totalCost > wallet.getActualBalance()) { p.destinations[0].amount = wallet.getActualBalance() - totalFee; } uint64_t amountPerTx = p.destinations[0].amount / numTransactions; uint64_t change = p.destinations[0].amount % numTransactions; std::vector<CryptoNote::TransactionParameters> transfers; for (int i = 0; i < numTransactions; i++) { CryptoNote::TransactionParameters tmp = p; tmp.destinations[0].amount = amountPerTx; tmp.fee = feePerTx; transfers.push_back(tmp); } transfers[0].destinations[0].amount += change; for (auto tx : transfers) { if (wallet.txIsTooLarge(tx)) { std::cout << "Split up transactions are still too large! " << "Splitting up into smaller chunks." << std::endl; continue; } } sendMultipleTransactions(wallet, transfers); return; } }
void splitTx(CryptoNote::WalletGreen &wallet, CryptoNote::TransactionParameters p) { std::cout << "Wallet optimization failed, transactions are still too large " << "to send in one chunk, splitting into multiple chunks." << std::endl << "This may take a long time as portions of your " << "balance get locked whilst sending a transaction." << std::endl << "It may also slightly raise the fee you have " << "to pay, and hence reduce the total amount you can send if " << "your balance cannot cover it." << std::endl; if (!confirm("Is this OK?")) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; return; } CryptoNote::TransactionParameters restoreInitialTx = p; uint64_t maxSize = wallet.getMaxTxSize(); size_t txSize = wallet.getTxSize(p); uint64_t minFee = CryptoNote::parameters::MINIMUM_FEE; for (int numTxMultiplier = 2; ; numTxMultiplier++) { /* We modify p a bit in this function, so restore back to initial state each time */ p = restoreInitialTx; /* We can't just evenly divide a transaction up to be < 115k bytes by decreasing the amount we're sending, because depending upon the inputs we might need to split into more transactions, so a good start is attempting to split them into chunks of 55k bytes or so. We then check at the end that each transaction is small enough, and if not, we up the numTxMultiplier and try again with more transactions. */ int numTransactions = int(numTxMultiplier * (std::ceil(double(txSize) / double(maxSize)))); /* Split the requested fee over each transaction, i.e. if a fee of 200 TRTL was requested and we split it into 4 transactions each one will have a fee of 5 TRTL. If the fee per transaction is less than the min fee, use the min fee. */ uint64_t feePerTx = std::max (p.fee / numTransactions, minFee); uint64_t totalFee = feePerTx * numTransactions; uint64_t totalCost = p.destinations[0].amount + totalFee; /* If we have to use the minimum fee instead of splitting the total fee, then it is possible the user no longer has the balance to cover this transaction. So, we slightly lower the amount they are sending. */ if (totalCost > wallet.getActualBalance()) { p.destinations[0].amount = wallet.getActualBalance() - totalFee; } uint64_t amountPerTx = p.destinations[0].amount / numTransactions; /* Left over amount from integral division */ uint64_t change = p.destinations[0].amount % numTransactions; std::vector<CryptoNote::TransactionParameters> transfers; for (int i = 0; i < numTransactions; i++) { CryptoNote::TransactionParameters tmp = p; tmp.destinations[0].amount = amountPerTx; tmp.fee = feePerTx; transfers.push_back(tmp); } /* Add the extra change to the first transaction */ transfers[0].destinations[0].amount += change; for (auto tx : transfers) { /* One of the transfers is too large. Retry, cutting the transactions into smaller pieces */ if (wallet.txIsTooLarge(tx)) { std::cout << "Split up transactions are still too large! " << "Splitting up into smaller chunks." << std::endl; continue; } } sendMultipleTransactions(wallet, transfers); return; } }