Merge pull request #5639
2eef90d6
rpc: restrict the recent cutoff size in restricted RPC mode (moneromooo-monero)0564da5f
ensure no NULL is passed to memcpy (moneromooo-monero)bc09766b
abstract_tcp_server2: improve DoS resistance (moneromooo-monero)1387549e
serialization: check stream good flag at the end (moneromooo-monero)a00cabd4
tree-hash: allocate variable memory on heap, not stack (moneromooo-monero)f2152192
cryptonote: throw on tx hash calculation error (moneromooo-monero)db2b9fba
serialization: fail on read_varint error (moneromooo-monero)68ad5481
cryptonote_protocol: fix another potential P2P DoS (moneromooo-monero)1cc61018
cryptonote_protocol: expand basic DoS protection (moneromooo-monero)8f66b705
cryptonote_protocol_handler: prevent potential DoS (anonimal)39169ace
epee: basic sanity check on allocation size from untrusted source (moneromooo-monero)
This commit is contained in:
commit
1d5e8f461d
|
@ -54,6 +54,9 @@
|
||||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||||
|
|
||||||
|
#define AGGRESSIVE_TIMEOUT_THRESHOLD 120 // sockets
|
||||||
|
#define NEW_CONNECTION_TIMEOUT_LOCAL 1200000 // 2 minutes
|
||||||
|
#define NEW_CONNECTION_TIMEOUT_REMOTE 10000 // 10 seconds
|
||||||
#define DEFAULT_TIMEOUT_MS_LOCAL 1800000 // 30 minutes
|
#define DEFAULT_TIMEOUT_MS_LOCAL 1800000 // 30 minutes
|
||||||
#define DEFAULT_TIMEOUT_MS_REMOTE 300000 // 5 minutes
|
#define DEFAULT_TIMEOUT_MS_REMOTE 300000 // 5 minutes
|
||||||
#define TIMEOUT_EXTRA_MS_PER_BYTE 0.2
|
#define TIMEOUT_EXTRA_MS_PER_BYTE 0.2
|
||||||
|
@ -189,7 +192,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
|
|
||||||
m_protocol_handler.after_init_connection();
|
m_protocol_handler.after_init_connection();
|
||||||
|
|
||||||
reset_timer(get_default_timeout(), false);
|
reset_timer(boost::posix_time::milliseconds(m_local ? NEW_CONNECTION_TIMEOUT_LOCAL : NEW_CONNECTION_TIMEOUT_REMOTE), false);
|
||||||
|
|
||||||
// first read on the raw socket to detect SSL for the server
|
// first read on the raw socket to detect SSL for the server
|
||||||
buffer_ssl_init_fill = 0;
|
buffer_ssl_init_fill = 0;
|
||||||
|
@ -691,7 +694,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
{
|
{
|
||||||
unsigned count;
|
unsigned count;
|
||||||
try { count = host_count(m_host); } catch (...) { count = 0; }
|
try { count = host_count(m_host); } catch (...) { count = 0; }
|
||||||
const unsigned shift = std::min(std::max(count, 1u) - 1, 8u);
|
const unsigned shift = get_state().sock_count > AGGRESSIVE_TIMEOUT_THRESHOLD ? std::min(std::max(count, 1u) - 1, 8u) : 0;
|
||||||
boost::posix_time::milliseconds timeout(0);
|
boost::posix_time::milliseconds timeout(0);
|
||||||
if (m_local)
|
if (m_local)
|
||||||
timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift);
|
timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift);
|
||||||
|
@ -730,8 +733,6 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
template<class t_protocol_handler>
|
template<class t_protocol_handler>
|
||||||
void connection<t_protocol_handler>::reset_timer(boost::posix_time::milliseconds ms, bool add)
|
void connection<t_protocol_handler>::reset_timer(boost::posix_time::milliseconds ms, bool add)
|
||||||
{
|
{
|
||||||
if (m_connection_type != e_connection_type_RPC)
|
|
||||||
return;
|
|
||||||
MTRACE("Setting " << ms << " expiry");
|
MTRACE("Setting " << ms << " expiry");
|
||||||
auto self = safe_shared_from_this();
|
auto self = safe_shared_from_this();
|
||||||
if(!self)
|
if(!self)
|
||||||
|
|
|
@ -136,6 +136,7 @@ namespace epee
|
||||||
//for pod types
|
//for pod types
|
||||||
array_entry_t<type_name> sa;
|
array_entry_t<type_name> sa;
|
||||||
size_t size = read_varint();
|
size_t size = read_varint();
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(size <= m_count, "Size sanity check failed");
|
||||||
sa.reserve(size);
|
sa.reserve(size);
|
||||||
//TODO: add some optimization here later
|
//TODO: add some optimization here later
|
||||||
while(size--)
|
while(size--)
|
||||||
|
|
|
@ -64,7 +64,8 @@ void buffer::append(const void *data, size_t sz)
|
||||||
size_t reserve = (((size() + sz) * 3 / 2) + 4095) & ~4095;
|
size_t reserve = (((size() + sz) * 3 / 2) + 4095) & ~4095;
|
||||||
new_storage.reserve(reserve);
|
new_storage.reserve(reserve);
|
||||||
new_storage.resize(size());
|
new_storage.resize(size());
|
||||||
memcpy(new_storage.data(), storage.data() + offset, storage.size() - offset);
|
if (size() > 0)
|
||||||
|
memcpy(new_storage.data(), storage.data() + offset, storage.size() - offset);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
std::swap(storage, new_storage);
|
std::swap(storage, new_storage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,13 +62,15 @@ wipeable_string::wipeable_string(wipeable_string &&other)
|
||||||
wipeable_string::wipeable_string(const std::string &other)
|
wipeable_string::wipeable_string(const std::string &other)
|
||||||
{
|
{
|
||||||
grow(other.size());
|
grow(other.size());
|
||||||
memcpy(buffer.data(), other.c_str(), size());
|
if (size() > 0)
|
||||||
|
memcpy(buffer.data(), other.c_str(), size());
|
||||||
}
|
}
|
||||||
|
|
||||||
wipeable_string::wipeable_string(std::string &&other)
|
wipeable_string::wipeable_string(std::string &&other)
|
||||||
{
|
{
|
||||||
grow(other.size());
|
grow(other.size());
|
||||||
memcpy(buffer.data(), other.c_str(), size());
|
if (size() > 0)
|
||||||
|
memcpy(buffer.data(), other.c_str(), size());
|
||||||
if (!other.empty())
|
if (!other.empty())
|
||||||
{
|
{
|
||||||
memwipe(&other[0], other.size()); // we're kinda left with this again aren't we
|
memwipe(&other[0], other.size()); // we're kinda left with this again aren't we
|
||||||
|
@ -79,7 +81,8 @@ wipeable_string::wipeable_string(std::string &&other)
|
||||||
wipeable_string::wipeable_string(const char *s)
|
wipeable_string::wipeable_string(const char *s)
|
||||||
{
|
{
|
||||||
grow(strlen(s));
|
grow(strlen(s));
|
||||||
memcpy(buffer.data(), s, size());
|
if (size() > 0)
|
||||||
|
memcpy(buffer.data(), s, size());
|
||||||
}
|
}
|
||||||
|
|
||||||
wipeable_string::wipeable_string(const char *s, size_t len)
|
wipeable_string::wipeable_string(const char *s, size_t len)
|
||||||
|
@ -112,14 +115,18 @@ void wipeable_string::grow(size_t sz, size_t reserved)
|
||||||
}
|
}
|
||||||
size_t old_sz = buffer.size();
|
size_t old_sz = buffer.size();
|
||||||
std::unique_ptr<char[]> tmp{new char[old_sz]};
|
std::unique_ptr<char[]> tmp{new char[old_sz]};
|
||||||
memcpy(tmp.get(), buffer.data(), old_sz * sizeof(char));
|
|
||||||
if (old_sz > 0)
|
if (old_sz > 0)
|
||||||
|
{
|
||||||
|
memcpy(tmp.get(), buffer.data(), old_sz * sizeof(char));
|
||||||
memwipe(buffer.data(), old_sz * sizeof(char));
|
memwipe(buffer.data(), old_sz * sizeof(char));
|
||||||
|
}
|
||||||
buffer.reserve(reserved);
|
buffer.reserve(reserved);
|
||||||
buffer.resize(sz);
|
buffer.resize(sz);
|
||||||
memcpy(buffer.data(), tmp.get(), old_sz * sizeof(char));
|
|
||||||
if (old_sz > 0)
|
if (old_sz > 0)
|
||||||
|
{
|
||||||
|
memcpy(buffer.data(), tmp.get(), old_sz * sizeof(char));
|
||||||
memwipe(tmp.get(), old_sz * sizeof(char));
|
memwipe(tmp.get(), old_sz * sizeof(char));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void wipeable_string::push_back(char c)
|
void wipeable_string::push_back(char c)
|
||||||
|
|
|
@ -1077,11 +1077,11 @@ void BlockchainLMDB::add_tx_amount_output_indices(const uint64_t tx_id,
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
int num_outputs = amount_output_indices.size();
|
size_t num_outputs = amount_output_indices.size();
|
||||||
|
|
||||||
MDB_val_set(k_tx_id, tx_id);
|
MDB_val_set(k_tx_id, tx_id);
|
||||||
MDB_val v;
|
MDB_val v;
|
||||||
v.mv_data = (void *)amount_output_indices.data();
|
v.mv_data = num_outputs ? (void *)amount_output_indices.data() : (void*)"";
|
||||||
v.mv_size = sizeof(uint64_t) * num_outputs;
|
v.mv_size = sizeof(uint64_t) * num_outputs;
|
||||||
// LOG_PRINT_L1("tx_outputs[tx_hash] size: " << v.mv_size);
|
// LOG_PRINT_L1("tx_outputs[tx_hash] size: " << v.mv_size);
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,8 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
|
||||||
local_abort("Bad keccak use");
|
local_abort("Bad keccak use");
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(temp, in, inlen);
|
if (inlen > 0)
|
||||||
|
memcpy(temp, in, inlen);
|
||||||
temp[inlen++] = 1;
|
temp[inlen++] = 1;
|
||||||
memset(temp + inlen, 0, rsiz - inlen);
|
memset(temp + inlen, 0, rsiz - inlen);
|
||||||
temp[rsiz - 1] |= 0x80;
|
temp[rsiz - 1] |= 0x80;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "hash-ops.h"
|
#include "hash-ops.h"
|
||||||
|
@ -82,23 +83,24 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
|
||||||
|
|
||||||
size_t cnt = tree_hash_cnt( count );
|
size_t cnt = tree_hash_cnt( count );
|
||||||
|
|
||||||
char ints[cnt][HASH_SIZE];
|
char *ints = calloc(cnt, HASH_SIZE); // zero out as extra protection for using uninitialized mem
|
||||||
memset(ints, 0 , sizeof(ints)); // zero out as extra protection for using uninitialized mem
|
assert(ints);
|
||||||
|
|
||||||
memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE);
|
memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE);
|
||||||
|
|
||||||
for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) {
|
for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) {
|
||||||
cn_fast_hash(hashes[i], 64, ints[j]);
|
cn_fast_hash(hashes[i], 64, ints + j * HASH_SIZE);
|
||||||
}
|
}
|
||||||
assert(i == count);
|
assert(i == count);
|
||||||
|
|
||||||
while (cnt > 2) {
|
while (cnt > 2) {
|
||||||
cnt >>= 1;
|
cnt >>= 1;
|
||||||
for (i = 0, j = 0; j < cnt; i += 2, ++j) {
|
for (i = 0, j = 0; j < cnt; i += 2, ++j) {
|
||||||
cn_fast_hash(ints[i], 64, ints[j]);
|
cn_fast_hash(ints + i * HASH_SIZE, 64, ints + j * HASH_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cn_fast_hash(ints[0], 64, root_hash);
|
cn_fast_hash(ints, 64, root_hash);
|
||||||
|
free(ints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,7 @@ namespace cryptonote
|
||||||
}
|
}
|
||||||
if (!typename Archive<W>::is_saving())
|
if (!typename Archive<W>::is_saving())
|
||||||
pruned = true;
|
pruned = true;
|
||||||
return true;
|
return ar.stream().good();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -221,8 +221,7 @@ namespace cryptonote
|
||||||
tx.invalidate_hashes();
|
tx.invalidate_hashes();
|
||||||
//TODO: validate tx
|
//TODO: validate tx
|
||||||
|
|
||||||
get_transaction_hash(tx, tx_hash);
|
return get_transaction_hash(tx, tx_hash);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
|
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
|
||||||
|
@ -975,6 +974,7 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
crypto::hash h = null_hash;
|
crypto::hash h = null_hash;
|
||||||
get_transaction_hash(t, h, NULL);
|
get_transaction_hash(t, h, NULL);
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(t, h, NULL), "Failed to calculate transaction hash");
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
@ -1327,7 +1327,7 @@ namespace cryptonote
|
||||||
txs_ids.reserve(1 + b.tx_hashes.size());
|
txs_ids.reserve(1 + b.tx_hashes.size());
|
||||||
crypto::hash h = null_hash;
|
crypto::hash h = null_hash;
|
||||||
size_t bl_sz = 0;
|
size_t bl_sz = 0;
|
||||||
get_transaction_hash(b.miner_tx, h, bl_sz);
|
CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.miner_tx, h, bl_sz), "Failed to calculate transaction hash");
|
||||||
txs_ids.push_back(h);
|
txs_ids.push_back(h);
|
||||||
for(auto& th: b.tx_hashes)
|
for(auto& th: b.tx_hashes)
|
||||||
txs_ids.push_back(th);
|
txs_ids.push_back(th);
|
||||||
|
|
|
@ -52,6 +52,7 @@ PUSH_WARNINGS
|
||||||
DISABLE_VS_WARNINGS(4355)
|
DISABLE_VS_WARNINGS(4355)
|
||||||
|
|
||||||
#define LOCALHOST_INT 2130706433
|
#define LOCALHOST_INT 2130706433
|
||||||
|
#define CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT 500
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
|
|
|
@ -809,12 +809,27 @@ namespace cryptonote
|
||||||
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
|
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
|
||||||
fluffy_response.b.block = t_serializable_object_to_blob(b);
|
fluffy_response.b.block = t_serializable_object_to_blob(b);
|
||||||
fluffy_response.current_blockchain_height = arg.current_blockchain_height;
|
fluffy_response.current_blockchain_height = arg.current_blockchain_height;
|
||||||
|
std::vector<bool> seen(b.tx_hashes.size(), false);
|
||||||
for(auto& tx_idx: arg.missing_tx_indices)
|
for(auto& tx_idx: arg.missing_tx_indices)
|
||||||
{
|
{
|
||||||
if(tx_idx < b.tx_hashes.size())
|
if(tx_idx < b.tx_hashes.size())
|
||||||
{
|
{
|
||||||
MDEBUG(" tx " << b.tx_hashes[tx_idx]);
|
MDEBUG(" tx " << b.tx_hashes[tx_idx]);
|
||||||
|
if (seen[tx_idx])
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT
|
||||||
|
(
|
||||||
|
"Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
|
||||||
|
<< ", request is asking for duplicate tx "
|
||||||
|
<< ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
|
||||||
|
<< ", block_height = " << arg.current_blockchain_height
|
||||||
|
<< ", dropping connection"
|
||||||
|
);
|
||||||
|
drop_connection(context, true, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
txids.push_back(b.tx_hashes[tx_idx]);
|
txids.push_back(b.tx_hashes[tx_idx]);
|
||||||
|
seen[tx_idx] = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -914,6 +929,17 @@ namespace cryptonote
|
||||||
int t_cryptonote_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
|
int t_cryptonote_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
|
||||||
{
|
{
|
||||||
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
|
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
|
||||||
|
|
||||||
|
if (arg.blocks.size() + arg.txs.size() > CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT)
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT(
|
||||||
|
"Requested objects count is too big ("
|
||||||
|
<< arg.blocks.size() + arg.txs.size() << ") expected not more then "
|
||||||
|
<< CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT);
|
||||||
|
drop_connection(context, false, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
NOTIFY_RESPONSE_GET_OBJECTS::request rsp;
|
NOTIFY_RESPONSE_GET_OBJECTS::request rsp;
|
||||||
if(!m_core.handle_get_objects(arg, rsp, context))
|
if(!m_core.handle_get_objects(arg, rsp, context))
|
||||||
{
|
{
|
||||||
|
|
|
@ -252,7 +252,7 @@ namespace rct {
|
||||||
{
|
{
|
||||||
FIELD(type)
|
FIELD(type)
|
||||||
if (type == RCTTypeNull)
|
if (type == RCTTypeNull)
|
||||||
return true;
|
return ar.stream().good();
|
||||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
|
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
|
||||||
return false;
|
return false;
|
||||||
VARINT_FIELD(txnFee)
|
VARINT_FIELD(txnFee)
|
||||||
|
@ -312,7 +312,7 @@ namespace rct {
|
||||||
ar.delimit_array();
|
ar.delimit_array();
|
||||||
}
|
}
|
||||||
ar.end_array();
|
ar.end_array();
|
||||||
return true;
|
return ar.stream().good();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
struct rctSigPrunable {
|
struct rctSigPrunable {
|
||||||
|
@ -325,7 +325,7 @@ namespace rct {
|
||||||
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
|
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
|
||||||
{
|
{
|
||||||
if (type == RCTTypeNull)
|
if (type == RCTTypeNull)
|
||||||
return true;
|
return ar.stream().good();
|
||||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
|
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
|
||||||
return false;
|
return false;
|
||||||
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2)
|
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2)
|
||||||
|
@ -429,7 +429,7 @@ namespace rct {
|
||||||
}
|
}
|
||||||
ar.end_array();
|
ar.end_array();
|
||||||
}
|
}
|
||||||
return true;
|
return ar.stream().good();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,6 +59,8 @@ using namespace epee;
|
||||||
#define MAX_RESTRICTED_FAKE_OUTS_COUNT 40
|
#define MAX_RESTRICTED_FAKE_OUTS_COUNT 40
|
||||||
#define MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT 5000
|
#define MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT 5000
|
||||||
|
|
||||||
|
#define OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION (3 * 86400) // 3 days max, the wallet requests 1.8 days
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void add_reason(std::string &reasons, const char *reason)
|
void add_reason(std::string &reasons, const char *reason)
|
||||||
|
@ -1882,6 +1884,13 @@ namespace cryptonote
|
||||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC, "get_output_histogram", req, res, r))
|
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC, "get_output_histogram", req, res, r))
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
const bool restricted = m_restricted && ctx;
|
||||||
|
if (restricted && req.recent_cutoff > 0 && req.recent_cutoff < (uint64_t)time(NULL) - OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION)
|
||||||
|
{
|
||||||
|
res.status = "Recent cutoff is too old";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
|
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -146,7 +146,8 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false>
|
||||||
void serialize_uvarint(T &v)
|
void serialize_uvarint(T &v)
|
||||||
{
|
{
|
||||||
typedef std::istreambuf_iterator<char> it;
|
typedef std::istreambuf_iterator<char> it;
|
||||||
tools::read_varint(it(stream_), it(), v); // XXX handle failure
|
if (tools::read_varint(it(stream_), it(), v) < 0)
|
||||||
|
stream_.setstate(std::ios_base::failbit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void begin_array(size_t &s)
|
void begin_array(size_t &s)
|
||||||
|
|
|
@ -212,7 +212,7 @@ inline bool do_serialize(Archive &ar, bool &v)
|
||||||
* \brief self-explanatory
|
* \brief self-explanatory
|
||||||
*/
|
*/
|
||||||
#define END_SERIALIZE() \
|
#define END_SERIALIZE() \
|
||||||
return true; \
|
return ar.stream().good(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \macro VALUE(f)
|
/*! \macro VALUE(f)
|
||||||
|
|
Loading…
Reference in New Issue