check accessing an element past the end of a container
This commit is contained in:
parent
2305bf260d
commit
b49ddc766d
|
@ -259,7 +259,7 @@ namespace cryptonote
|
||||||
ar.tag("rctsig_prunable");
|
ar.tag("rctsig_prunable");
|
||||||
ar.begin_object();
|
ar.begin_object();
|
||||||
r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(),
|
r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(),
|
||||||
vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0);
|
vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0);
|
||||||
if (!r || !ar.stream().good()) return false;
|
if (!r || !ar.stream().good()) return false;
|
||||||
ar.end_object();
|
ar.end_object();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2338,7 +2338,7 @@ void Blockchain::on_new_tx_from_block(const cryptonote::transaction &tx)
|
||||||
TIME_MEASURE_FINISH(a);
|
TIME_MEASURE_FINISH(a);
|
||||||
if(m_show_time_stats)
|
if(m_show_time_stats)
|
||||||
{
|
{
|
||||||
size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
|
size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
|
||||||
MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a);
|
MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2373,7 +2373,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_heigh
|
||||||
TIME_MEASURE_FINISH(a);
|
TIME_MEASURE_FINISH(a);
|
||||||
if(m_show_time_stats)
|
if(m_show_time_stats)
|
||||||
{
|
{
|
||||||
size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
|
size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
|
||||||
MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx));
|
MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx));
|
||||||
}
|
}
|
||||||
if (!res)
|
if (!res)
|
||||||
|
@ -2466,6 +2466,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||||
// mixRing - full and simple store it in opposite ways
|
// mixRing - full and simple store it in opposite ways
|
||||||
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
||||||
{
|
{
|
||||||
|
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
|
||||||
rv.mixRing.resize(pubkeys[0].size());
|
rv.mixRing.resize(pubkeys[0].size());
|
||||||
for (size_t m = 0; m < pubkeys[0].size(); ++m)
|
for (size_t m = 0; m < pubkeys[0].size(); ++m)
|
||||||
rv.mixRing[m].clear();
|
rv.mixRing[m].clear();
|
||||||
|
@ -2480,6 +2481,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||||
}
|
}
|
||||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof)
|
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof)
|
||||||
{
|
{
|
||||||
|
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
|
||||||
rv.mixRing.resize(pubkeys.size());
|
rv.mixRing.resize(pubkeys.size());
|
||||||
for (size_t n = 0; n < pubkeys.size(); ++n)
|
for (size_t n = 0; n < pubkeys.size(); ++n)
|
||||||
{
|
{
|
||||||
|
@ -2811,7 +2813,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||||
}
|
}
|
||||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||||
{
|
{
|
||||||
if (memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32))
|
if (rv.p.MGs[n].II.empty() || memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32))
|
||||||
{
|
{
|
||||||
MERROR_VER("Failed to check ringct signatures: mismatched key image");
|
MERROR_VER("Failed to check ringct signatures: mismatched key image");
|
||||||
return false;
|
return false;
|
||||||
|
@ -2864,7 +2866,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||||
MERROR_VER("Failed to check ringct signatures: Bad MGs size");
|
MERROR_VER("Failed to check ringct signatures: Bad MGs size");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (rv.p.MGs[0].II.size() != tx.vin.size())
|
if (rv.p.MGs.empty() || rv.p.MGs[0].II.size() != tx.vin.size())
|
||||||
{
|
{
|
||||||
MERROR_VER("Failed to check ringct signatures: mismatched II/vin sizes");
|
MERROR_VER("Failed to check ringct signatures: mismatched II/vin sizes");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -190,6 +190,12 @@ namespace cryptonote
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
|
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
|
||||||
{
|
{
|
||||||
|
if (sources.empty())
|
||||||
|
{
|
||||||
|
LOG_ERROR("Empty sources");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<rct::key> amount_keys;
|
std::vector<rct::key> amount_keys;
|
||||||
tx.set_null();
|
tx.set_null();
|
||||||
amount_keys.clear();
|
amount_keys.clear();
|
||||||
|
|
|
@ -76,6 +76,7 @@ namespace rct {
|
||||||
//Generates a vector of secret key
|
//Generates a vector of secret key
|
||||||
//Mainly used in testing
|
//Mainly used in testing
|
||||||
keyV skvGen(size_t rows ) {
|
keyV skvGen(size_t rows ) {
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(rows > 0, "0 keys requested");
|
||||||
keyV rv(rows);
|
keyV rv(rows);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]);
|
crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]);
|
||||||
|
@ -351,6 +352,7 @@ namespace rct {
|
||||||
//This takes the outputs and commitments
|
//This takes the outputs and commitments
|
||||||
//and hashes them into a 32 byte sized key
|
//and hashes them into a 32 byte sized key
|
||||||
key cn_fast_hash(const ctkeyV &PC) {
|
key cn_fast_hash(const ctkeyV &PC) {
|
||||||
|
if (PC.empty()) return rct::hash2rct(crypto::cn_fast_hash("", 0));
|
||||||
key rv;
|
key rv;
|
||||||
cn_fast_hash(rv, &PC[0], 64*PC.size());
|
cn_fast_hash(rv, &PC[0], 64*PC.size());
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -367,6 +369,7 @@ namespace rct {
|
||||||
//put them in the key vector and it concatenates them
|
//put them in the key vector and it concatenates them
|
||||||
//and then hashes them
|
//and then hashes them
|
||||||
key cn_fast_hash(const keyV &keys) {
|
key cn_fast_hash(const keyV &keys) {
|
||||||
|
if (keys.empty()) return rct::hash2rct(crypto::cn_fast_hash("", 0));
|
||||||
key rv;
|
key rv;
|
||||||
cn_fast_hash(rv, &keys[0], keys.size() * sizeof(keys[0]));
|
cn_fast_hash(rv, &keys[0], keys.size() * sizeof(keys[0]));
|
||||||
//dp(rv);
|
//dp(rv);
|
||||||
|
|
|
@ -293,6 +293,10 @@ std::vector<std::string> UnsignedTransactionImpl::recipientAddress() const
|
||||||
// TODO: return integrated address if short payment ID exists
|
// TODO: return integrated address if short payment ID exists
|
||||||
std::vector<string> result;
|
std::vector<string> result;
|
||||||
for (const auto &utx: m_unsigned_tx_set.txes) {
|
for (const auto &utx: m_unsigned_tx_set.txes) {
|
||||||
|
if (utx.dests.empty()) {
|
||||||
|
MERROR("empty destinations, skipped");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].is_subaddress, utx.dests[0].addr));
|
result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].is_subaddress, utx.dests[0].addr));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -540,6 +540,11 @@ crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx)
|
||||||
{
|
{
|
||||||
if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
|
if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
|
||||||
{
|
{
|
||||||
|
if (ptx.dests.empty())
|
||||||
|
{
|
||||||
|
MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt");
|
||||||
|
return crypto::null_hash8;
|
||||||
|
}
|
||||||
decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key);
|
decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4050,6 +4055,11 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
|
||||||
crypto::hash8 payment_id8 = null_hash8;
|
crypto::hash8 payment_id8 = null_hash8;
|
||||||
if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
|
if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
|
||||||
{
|
{
|
||||||
|
if (ptx.dests.empty())
|
||||||
|
{
|
||||||
|
MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt");
|
||||||
|
return crypto::null_hash;
|
||||||
|
}
|
||||||
if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key))
|
if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key))
|
||||||
{
|
{
|
||||||
memcpy(payment_id.data, payment_id8.data, 8);
|
memcpy(payment_id.data, payment_id8.data, 8);
|
||||||
|
@ -4274,6 +4284,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
|
||||||
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
|
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
|
||||||
{
|
{
|
||||||
tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
|
tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
|
||||||
|
THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources");
|
||||||
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
|
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
|
||||||
signed_txes.ptx.push_back(pending_tx());
|
signed_txes.ptx.push_back(pending_tx());
|
||||||
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
|
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
|
||||||
|
@ -6637,7 +6648,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
LOG_PRINT_L2("Made a " << ((txBlob.size() + 1023) / 1024) << " kB tx, with " << print_money(available_for_fee) << " available for fee (" <<
|
LOG_PRINT_L2("Made a " << ((txBlob.size() + 1023) / 1024) << " kB tx, with " << print_money(available_for_fee) << " available for fee (" <<
|
||||||
print_money(needed_fee) << " needed)");
|
print_money(needed_fee) << " needed)");
|
||||||
|
|
||||||
if (needed_fee > available_for_fee && dsts[0].amount > 0)
|
if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0)
|
||||||
{
|
{
|
||||||
// we don't have enough for the fee, but we've only partially paid the current address,
|
// we don't have enough for the fee, but we've only partially paid the current address,
|
||||||
// so we can take the fee from the paid amount, since we'll have to make another tx anyway
|
// so we can take the fee from the paid amount, since we'll have to make another tx anyway
|
||||||
|
@ -8912,6 +8923,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
|
||||||
throw std::runtime_error(oss.str());
|
throw std::runtime_error(oss.str());
|
||||||
}
|
}
|
||||||
cryptonote::block blk_min, blk_mid, blk_max;
|
cryptonote::block blk_min, blk_mid, blk_max;
|
||||||
|
if (res.blocks.size() < 3) throw std::runtime_error("Not enough blocks returned from daemon");
|
||||||
if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_min));
|
if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_min));
|
||||||
if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_mid));
|
if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_mid));
|
||||||
if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_max));
|
if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_max));
|
||||||
|
|
|
@ -486,7 +486,7 @@ namespace tools
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er)
|
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
crypto::hash8 integrated_payment_id = crypto::null_hash8;
|
crypto::hash8 integrated_payment_id = crypto::null_hash8;
|
||||||
std::string extra_nonce;
|
std::string extra_nonce;
|
||||||
|
@ -541,6 +541,13 @@ namespace tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (at_least_one_destination && dsts.empty())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_ZERO_DESTINATION;
|
||||||
|
er.message = "No destinations for this transfer";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!payment_id.empty())
|
if (!payment_id.empty())
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -592,7 +599,7 @@ namespace tools
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate the transfer requested and populate dsts & extra
|
// validate the transfer requested and populate dsts & extra
|
||||||
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er))
|
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -690,7 +697,7 @@ namespace tools
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types.
|
// validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types.
|
||||||
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er))
|
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -887,7 +894,7 @@ namespace tools
|
||||||
destination.push_back(wallet_rpc::transfer_destination());
|
destination.push_back(wallet_rpc::transfer_destination());
|
||||||
destination.back().amount = 0;
|
destination.back().amount = 0;
|
||||||
destination.back().address = req.address;
|
destination.back().address = req.address;
|
||||||
if (!validate_transfer(destination, req.payment_id, dsts, extra, er))
|
if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -986,7 +993,7 @@ namespace tools
|
||||||
destination.push_back(wallet_rpc::transfer_destination());
|
destination.push_back(wallet_rpc::transfer_destination());
|
||||||
destination.back().amount = 0;
|
destination.back().amount = 0;
|
||||||
destination.back().address = req.address;
|
destination.back().address = req.address;
|
||||||
if (!validate_transfer(destination, req.payment_id, dsts, extra, er))
|
if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace tools
|
||||||
bool on_create_account(const wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::response& res, epee::json_rpc::error& er);
|
bool on_create_account(const wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::response& res, epee::json_rpc::error& er);
|
||||||
bool on_label_account(const wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::response& res, epee::json_rpc::error& er);
|
bool on_label_account(const wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::response& res, epee::json_rpc::error& er);
|
||||||
bool on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er);
|
bool on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er);
|
||||||
bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er);
|
bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er);
|
||||||
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er);
|
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er);
|
||||||
bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er);
|
bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er);
|
||||||
bool on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er);
|
bool on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er);
|
||||||
|
|
Loading…
Reference in New Issue