protocol: option to pad transaction relay to the next kB

To help protect one's privacy from traffic volume analysis
for people using Tor or I2P. This will really fly once we
relay txes on a timer rather than on demand, though.

Off by default for now since it's wasteful and doesn't bring
anything until I2P's in.
This commit is contained in:
moneromooo-monero 2018-11-02 22:27:25 +00:00
parent 963d247154
commit 3dba7f252e
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
6 changed files with 52 additions and 1 deletions

View file

@ -163,6 +163,11 @@ namespace cryptonote
, "Relay blocks as normal blocks" , "Relay blocks as normal blocks"
, false , false
}; };
static const command_line::arg_descriptor<bool> arg_pad_transactions = {
"pad-transactions"
, "Pad relayed transactions to help defend against traffic volume analysis"
, false
};
static const command_line::arg_descriptor<size_t> arg_max_txpool_weight = { static const command_line::arg_descriptor<size_t> arg_max_txpool_weight = {
"max-txpool-weight" "max-txpool-weight"
, "Set maximum txpool weight in bytes." , "Set maximum txpool weight in bytes."
@ -188,7 +193,8 @@ namespace cryptonote
m_disable_dns_checkpoints(false), m_disable_dns_checkpoints(false),
m_update_download(0), m_update_download(0),
m_nettype(UNDEFINED), m_nettype(UNDEFINED),
m_update_available(false) m_update_available(false),
m_pad_transactions(false)
{ {
m_checkpoints_updating.clear(); m_checkpoints_updating.clear();
set_cryptonote_protocol(pprotocol); set_cryptonote_protocol(pprotocol);
@ -282,6 +288,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_offline); command_line::add_arg(desc, arg_offline);
command_line::add_arg(desc, arg_disable_dns_checkpoints); command_line::add_arg(desc, arg_disable_dns_checkpoints);
command_line::add_arg(desc, arg_max_txpool_weight); command_line::add_arg(desc, arg_max_txpool_weight);
command_line::add_arg(desc, arg_pad_transactions);
command_line::add_arg(desc, arg_block_notify); command_line::add_arg(desc, arg_block_notify);
miner::init_options(desc); miner::init_options(desc);
@ -320,6 +327,7 @@ namespace cryptonote
set_enforce_dns_checkpoints(command_line::get_arg(vm, arg_dns_checkpoints)); set_enforce_dns_checkpoints(command_line::get_arg(vm, arg_dns_checkpoints));
test_drop_download_height(command_line::get_arg(vm, arg_test_drop_download_height)); test_drop_download_height(command_line::get_arg(vm, arg_test_drop_download_height));
m_fluffy_blocks_enabled = !get_arg(vm, arg_no_fluffy_blocks); m_fluffy_blocks_enabled = !get_arg(vm, arg_no_fluffy_blocks);
m_pad_transactions = get_arg(vm, arg_pad_transactions);
m_offline = get_arg(vm, arg_offline); m_offline = get_arg(vm, arg_offline);
m_disable_dns_checkpoints = get_arg(vm, arg_disable_dns_checkpoints); m_disable_dns_checkpoints = get_arg(vm, arg_disable_dns_checkpoints);
if (!command_line::is_arg_defaulted(vm, arg_fluffy_blocks)) if (!command_line::is_arg_defaulted(vm, arg_fluffy_blocks))

View file

@ -756,6 +756,13 @@ namespace cryptonote
*/ */
bool fluffy_blocks_enabled() const { return m_fluffy_blocks_enabled; } bool fluffy_blocks_enabled() const { return m_fluffy_blocks_enabled; }
/**
* @brief get whether transaction relay should be padded
*
* @return whether transaction relay should be padded
*/
bool pad_transactions() const { return m_pad_transactions; }
/** /**
* @brief check a set of hashes against the precompiled hash set * @brief check a set of hashes against the precompiled hash set
* *
@ -1014,6 +1021,7 @@ namespace cryptonote
bool m_fluffy_blocks_enabled; bool m_fluffy_blocks_enabled;
bool m_offline; bool m_offline;
bool m_pad_transactions;
}; };
} }

View file

@ -146,9 +146,11 @@ namespace cryptonote
struct request struct request
{ {
std::vector<blobdata> txs; std::vector<blobdata> txs;
std::string _; // padding
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs) KV_SERIALIZE(txs)
KV_SERIALIZE(_)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
}; };

View file

@ -1724,8 +1724,39 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context) bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
{ {
// no check for success, so tell core they're relayed unconditionally // no check for success, so tell core they're relayed unconditionally
const bool pad_transactions = m_core.pad_transactions();
size_t bytes = pad_transactions ? 9 /* header */ + 4 /* 1 + 'txs' */ + tools::get_varint_data(arg.txs.size()).size() : 0;
for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end(); ++tx_blob_it) for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end(); ++tx_blob_it)
{
m_core.on_transaction_relayed(*tx_blob_it); m_core.on_transaction_relayed(*tx_blob_it);
if (pad_transactions)
bytes += tools::get_varint_data(tx_blob_it->size()).size() + tx_blob_it->size();
}
if (pad_transactions)
{
// stuff some dummy bytes in to stay safe from traffic volume analysis
static constexpr size_t granularity = 1024;
size_t padding = granularity - bytes % granularity;
const size_t overhead = 2 /* 1 + '_' */ + tools::get_varint_data(padding).size();
if (overhead > padding)
padding = 0;
else
padding -= overhead;
arg._ = std::string(padding, ' ');
std::string arg_buff;
epee::serialization::store_t_to_binary(arg, arg_buff);
// we probably lowballed the payload size a bit, so added a but too much. Fix this now.
size_t remove = arg_buff.size() % granularity;
if (remove > arg._.size())
arg._.clear();
else
arg._.resize(arg._.size() - remove);
// if the size of _ moved enough, we might lose byte in size encoding, we don't care
}
return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context); return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context);
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------

View file

@ -104,5 +104,6 @@ namespace tests
cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; } cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; }
bool fluffy_blocks_enabled() const { return false; } bool fluffy_blocks_enabled() const { return false; }
uint64_t prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes) { return 0; } uint64_t prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes) { return 0; }
bool pad_transactions() const { return false; }
}; };
} }

View file

@ -83,6 +83,7 @@ public:
cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; } cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; }
bool fluffy_blocks_enabled() const { return false; } bool fluffy_blocks_enabled() const { return false; }
uint64_t prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes) { return 0; } uint64_t prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes) { return 0; }
bool pad_transactions() { return false; }
void stop() {} void stop() {}
}; };