mirror of
https://git.wownero.com/wownero/wownero.git
synced 2024-08-15 01:03:23 +00:00
commit
29ebcc4e7e
26 changed files with 543 additions and 172 deletions
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
|
@ -16,17 +16,19 @@ jobs:
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: msys2 {0}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- uses: numworks/setup-msys2@v1
|
- uses: eine/setup-msys2@v1
|
||||||
- name: update pacman
|
with:
|
||||||
run: msys2do pacman -Syu --noconfirm
|
update: true
|
||||||
- name: install monero dependencies
|
install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb git
|
||||||
run: msys2do pacman -S --noconfirm mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb git
|
|
||||||
- name: build
|
- name: build
|
||||||
run: msys2do make release-static-win64 -j2
|
run: make release-static-win64 -j2
|
||||||
|
|
||||||
build-ubuntu:
|
build-ubuntu:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -277,7 +277,7 @@ namespace md5
|
||||||
/* Zeroize sensitive information.
|
/* Zeroize sensitive information.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
MD5_memset ((POINTER)context, 0, sizeof (*context));
|
memwipe ((POINTER)context, sizeof (*context));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MD5 basic transformation. Transforms state based on block.
|
/* MD5 basic transformation. Transforms state based on block.
|
||||||
|
@ -369,7 +369,7 @@ namespace md5
|
||||||
|
|
||||||
/* Zeroize sensitive information.
|
/* Zeroize sensitive information.
|
||||||
*/
|
*/
|
||||||
MD5_memset ((POINTER)x, 0, sizeof (x));
|
memwipe ((POINTER)x, sizeof (x));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: Replace "for loop" with standard memcpy if possible.
|
/* Note: Replace "for loop" with standard memcpy if possible.
|
||||||
|
@ -431,9 +431,9 @@ namespace md5
|
||||||
MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
|
MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
|
||||||
|
|
||||||
/* scrub the pads and key context (if used) */
|
/* scrub the pads and key context (if used) */
|
||||||
MD5_memset( (POINTER)&k_ipad, 0, sizeof(k_ipad));
|
memwipe( (POINTER)&k_ipad, sizeof(k_ipad));
|
||||||
MD5_memset( (POINTER)&k_opad, 0, sizeof(k_opad));
|
memwipe( (POINTER)&k_opad, sizeof(k_opad));
|
||||||
MD5_memset( (POINTER)&tk, 0, sizeof(tk));
|
memwipe( (POINTER)&tk, sizeof(tk));
|
||||||
|
|
||||||
/* and we're done. */
|
/* and we're done. */
|
||||||
}
|
}
|
||||||
|
@ -459,7 +459,7 @@ namespace md5
|
||||||
state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
|
state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
|
||||||
state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
|
state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
|
||||||
}
|
}
|
||||||
MD5_memset( (POINTER)&hmac, 0, sizeof(hmac));
|
memwipe( (POINTER)&hmac, sizeof(hmac));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -133,10 +133,13 @@ namespace epee
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
byte_slice::byte_slice(const adapt_buffer, T&& buffer)
|
byte_slice::byte_slice(const adapt_buffer, T&& buffer)
|
||||||
: storage_(nullptr), portion_(to_byte_span(to_span(buffer)))
|
: storage_(nullptr), portion_(nullptr)
|
||||||
{
|
{
|
||||||
if (!buffer.empty())
|
if (!buffer.empty())
|
||||||
|
{
|
||||||
storage_ = allocate_slice<adapted_byte_slice<T>>(0, std::move(buffer));
|
storage_ = allocate_slice<adapted_byte_slice<T>>(0, std::move(buffer));
|
||||||
|
portion_ = to_byte_span(to_span(static_cast<adapted_byte_slice<T> *>(storage_.get())->buffer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_slice::byte_slice(std::initializer_list<span<const std::uint8_t>> sources)
|
byte_slice::byte_slice(std::initializer_list<span<const std::uint8_t>> sources)
|
||||||
|
|
|
@ -511,7 +511,7 @@ bool ssl_options_t::handshake(
|
||||||
// autodetect will reconnect without SSL - warn and keep connection encrypted
|
// autodetect will reconnect without SSL - warn and keep connection encrypted
|
||||||
if (support != ssl_support_t::e_ssl_support_autodetect)
|
if (support != ssl_support_t::e_ssl_support_autodetect)
|
||||||
{
|
{
|
||||||
MERROR("SSL certificate is not in the allowed list, connection droppped");
|
MERROR("SSL certificate is not in the allowed list, connection dropped");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MWARNING("SSL peer has not been verified");
|
MWARNING("SSL peer has not been verified");
|
||||||
|
|
96
external/easylogging++/easylogging++.cc
vendored
96
external/easylogging++/easylogging++.cc
vendored
|
@ -2475,6 +2475,100 @@ void DefaultLogDispatchCallback::handle(const LogDispatchData* data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Transform>
|
||||||
|
static inline std::string utf8canonical(const std::string &s, Transform t = [](wint_t c)->wint_t { return c; })
|
||||||
|
{
|
||||||
|
std::string sc = "";
|
||||||
|
size_t avail = s.size();
|
||||||
|
const char *ptr = s.data();
|
||||||
|
wint_t cp = 0;
|
||||||
|
int bytes = 1;
|
||||||
|
char wbuf[8], *wptr;
|
||||||
|
while (avail--)
|
||||||
|
{
|
||||||
|
if ((*ptr & 0x80) == 0)
|
||||||
|
{
|
||||||
|
cp = *ptr++;
|
||||||
|
bytes = 1;
|
||||||
|
}
|
||||||
|
else if ((*ptr & 0xe0) == 0xc0)
|
||||||
|
{
|
||||||
|
if (avail < 1)
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
cp = (*ptr++ & 0x1f) << 6;
|
||||||
|
cp |= *ptr++ & 0x3f;
|
||||||
|
--avail;
|
||||||
|
bytes = 2;
|
||||||
|
}
|
||||||
|
else if ((*ptr & 0xf0) == 0xe0)
|
||||||
|
{
|
||||||
|
if (avail < 2)
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
cp = (*ptr++ & 0xf) << 12;
|
||||||
|
cp |= (*ptr++ & 0x3f) << 6;
|
||||||
|
cp |= *ptr++ & 0x3f;
|
||||||
|
avail -= 2;
|
||||||
|
bytes = 3;
|
||||||
|
}
|
||||||
|
else if ((*ptr & 0xf8) == 0xf0)
|
||||||
|
{
|
||||||
|
if (avail < 3)
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
cp = (*ptr++ & 0x7) << 18;
|
||||||
|
cp |= (*ptr++ & 0x3f) << 12;
|
||||||
|
cp |= (*ptr++ & 0x3f) << 6;
|
||||||
|
cp |= *ptr++ & 0x3f;
|
||||||
|
avail -= 3;
|
||||||
|
bytes = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
|
||||||
|
cp = t(cp);
|
||||||
|
if (cp <= 0x7f)
|
||||||
|
bytes = 1;
|
||||||
|
else if (cp <= 0x7ff)
|
||||||
|
bytes = 2;
|
||||||
|
else if (cp <= 0xffff)
|
||||||
|
bytes = 3;
|
||||||
|
else if (cp <= 0x10ffff)
|
||||||
|
bytes = 4;
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid code point UTF-8 transformation");
|
||||||
|
|
||||||
|
wptr = wbuf;
|
||||||
|
switch (bytes)
|
||||||
|
{
|
||||||
|
case 1: *wptr++ = cp; break;
|
||||||
|
case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
|
||||||
|
case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
|
||||||
|
case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
|
||||||
|
default: throw std::runtime_error("Invalid UTF-8");
|
||||||
|
}
|
||||||
|
*wptr = 0;
|
||||||
|
sc.append(wbuf, bytes);
|
||||||
|
cp = 0;
|
||||||
|
bytes = 1;
|
||||||
|
}
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sanitize(std::string &s)
|
||||||
|
{
|
||||||
|
s = utf8canonical(s, [](wint_t c)->wint_t {
|
||||||
|
if (c == 9 || c == 10 || c == 13)
|
||||||
|
return c;
|
||||||
|
if (c < 0x20)
|
||||||
|
return '?';
|
||||||
|
if (c == 0x7f)
|
||||||
|
return '?';
|
||||||
|
if (c >= 0x80 && c <= 0x9f)
|
||||||
|
return '?';
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix, base::type::string_t&& rawLinePayload, base::type::string_t&& logLine) {
|
void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix, base::type::string_t&& rawLinePayload, base::type::string_t&& logLine) {
|
||||||
if (m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog) {
|
if (m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog) {
|
||||||
if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
|
if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
|
||||||
|
@ -2506,6 +2600,8 @@ void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix,
|
||||||
m_data->logMessage()->logger()->logBuilder()->setColor(el::base::utils::colorFromLevel(level), false);
|
m_data->logMessage()->logger()->logBuilder()->setColor(el::base::utils::colorFromLevel(level), false);
|
||||||
ELPP_COUT << rawLinePrefix;
|
ELPP_COUT << rawLinePrefix;
|
||||||
m_data->logMessage()->logger()->logBuilder()->setColor(color == el::Color::Default ? el::base::utils::colorFromLevel(level): color, color != el::Color::Default);
|
m_data->logMessage()->logger()->logBuilder()->setColor(color == el::Color::Default ? el::base::utils::colorFromLevel(level): color, color != el::Color::Default);
|
||||||
|
try { sanitize(rawLinePayload); }
|
||||||
|
catch (const std::exception &e) { rawLinePayload = "<Invalid UTF-8 in log>"; }
|
||||||
ELPP_COUT << rawLinePayload;
|
ELPP_COUT << rawLinePayload;
|
||||||
m_data->logMessage()->logger()->logBuilder()->setColor(el::Color::Default, false);
|
m_data->logMessage()->logger()->logBuilder()->setColor(el::Color::Default, false);
|
||||||
ELPP_COUT << std::flush;
|
ELPP_COUT << std::flush;
|
||||||
|
|
|
@ -4048,7 +4048,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
|
||||||
void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial) const
|
void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial) const
|
||||||
{
|
{
|
||||||
if (amounts.size() != 1 && amounts.size() != offsets.size())
|
if (amounts.size() != 1 && amounts.size() != offsets.size())
|
||||||
throw0(DB_ERROR("Invalid sizes of amounts and offets"));
|
throw0(DB_ERROR("Invalid sizes of amounts and offsets"));
|
||||||
|
|
||||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||||
TIME_MEASURE_START(db3);
|
TIME_MEASURE_START(db3);
|
||||||
|
|
|
@ -86,7 +86,8 @@ set(common_private_headers
|
||||||
updates.h
|
updates.h
|
||||||
aligned.h
|
aligned.h
|
||||||
timings.h
|
timings.h
|
||||||
combinator.h)
|
combinator.h
|
||||||
|
utf8.h)
|
||||||
|
|
||||||
monero_private_headers(common
|
monero_private_headers(common
|
||||||
${common_private_headers})
|
${common_private_headers})
|
||||||
|
|
114
src/common/utf8.h
Normal file
114
src/common/utf8.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright (c) 2019, The Monero Project
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
// permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
// of conditions and the following disclaimer in the documentation and/or other
|
||||||
|
// materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace tools
|
||||||
|
{
|
||||||
|
template<typename T, typename Transform>
|
||||||
|
inline T utf8canonical(const T &s, Transform t = [](wint_t c)->wint_t { return c; })
|
||||||
|
{
|
||||||
|
T sc = "";
|
||||||
|
size_t avail = s.size();
|
||||||
|
const char *ptr = s.data();
|
||||||
|
wint_t cp = 0;
|
||||||
|
int bytes = 1;
|
||||||
|
char wbuf[8], *wptr;
|
||||||
|
while (avail--)
|
||||||
|
{
|
||||||
|
if ((*ptr & 0x80) == 0)
|
||||||
|
{
|
||||||
|
cp = *ptr++;
|
||||||
|
bytes = 1;
|
||||||
|
}
|
||||||
|
else if ((*ptr & 0xe0) == 0xc0)
|
||||||
|
{
|
||||||
|
if (avail < 1)
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
cp = (*ptr++ & 0x1f) << 6;
|
||||||
|
cp |= *ptr++ & 0x3f;
|
||||||
|
--avail;
|
||||||
|
bytes = 2;
|
||||||
|
}
|
||||||
|
else if ((*ptr & 0xf0) == 0xe0)
|
||||||
|
{
|
||||||
|
if (avail < 2)
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
cp = (*ptr++ & 0xf) << 12;
|
||||||
|
cp |= (*ptr++ & 0x3f) << 6;
|
||||||
|
cp |= *ptr++ & 0x3f;
|
||||||
|
avail -= 2;
|
||||||
|
bytes = 3;
|
||||||
|
}
|
||||||
|
else if ((*ptr & 0xf8) == 0xf0)
|
||||||
|
{
|
||||||
|
if (avail < 3)
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
cp = (*ptr++ & 0x7) << 18;
|
||||||
|
cp |= (*ptr++ & 0x3f) << 12;
|
||||||
|
cp |= (*ptr++ & 0x3f) << 6;
|
||||||
|
cp |= *ptr++ & 0x3f;
|
||||||
|
avail -= 3;
|
||||||
|
bytes = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid UTF-8");
|
||||||
|
|
||||||
|
cp = t(cp);
|
||||||
|
if (cp <= 0x7f)
|
||||||
|
bytes = 1;
|
||||||
|
else if (cp <= 0x7ff)
|
||||||
|
bytes = 2;
|
||||||
|
else if (cp <= 0xffff)
|
||||||
|
bytes = 3;
|
||||||
|
else if (cp <= 0x10ffff)
|
||||||
|
bytes = 4;
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid code point UTF-8 transformation");
|
||||||
|
|
||||||
|
wptr = wbuf;
|
||||||
|
switch (bytes)
|
||||||
|
{
|
||||||
|
case 1: *wptr++ = cp; break;
|
||||||
|
case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
|
||||||
|
case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
|
||||||
|
case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
|
||||||
|
default: throw std::runtime_error("Invalid UTF-8");
|
||||||
|
}
|
||||||
|
*wptr = 0;
|
||||||
|
sc.append(wbuf, bytes);
|
||||||
|
cp = 0;
|
||||||
|
bytes = 1;
|
||||||
|
}
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
}
|
|
@ -812,12 +812,20 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
|
||||||
// less blocks than desired if there aren't enough.
|
// less blocks than desired if there aren't enough.
|
||||||
difficulty_type Blockchain::get_difficulty_for_next_block()
|
difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
{
|
{
|
||||||
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
bool print = false;
|
||||||
|
|
||||||
|
int done = 0;
|
||||||
|
ss << "get_difficulty_for_next_block: height " << m_db->height() << std::endl;
|
||||||
if (m_fixed_difficulty)
|
if (m_fixed_difficulty)
|
||||||
{
|
{
|
||||||
return m_db->height() ? m_fixed_difficulty : 1;
|
return m_db->height() ? m_fixed_difficulty : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
start:
|
||||||
|
difficulty_type D = 0;
|
||||||
|
|
||||||
crypto::hash top_hash = get_tail_id();
|
crypto::hash top_hash = get_tail_id();
|
||||||
{
|
{
|
||||||
|
@ -826,25 +834,32 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
// something a bit out of date, but that's fine since anything which
|
// something a bit out of date, but that's fine since anything which
|
||||||
// requires the blockchain lock will have acquired it in the first place,
|
// requires the blockchain lock will have acquired it in the first place,
|
||||||
// and it will be unlocked only when called from the getinfo RPC
|
// and it will be unlocked only when called from the getinfo RPC
|
||||||
|
ss << "Locked, tail id " << top_hash << ", cached is " << m_difficulty_for_next_block_top_hash << std::endl;
|
||||||
if (top_hash == m_difficulty_for_next_block_top_hash)
|
if (top_hash == m_difficulty_for_next_block_top_hash)
|
||||||
return m_difficulty_for_next_block;
|
{
|
||||||
|
ss << "Same, using cached diff " << m_difficulty_for_next_block << std::endl;
|
||||||
|
D = m_difficulty_for_next_block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||||
std::vector<uint64_t> timestamps;
|
std::vector<uint64_t> timestamps;
|
||||||
std::vector<difficulty_type> difficulties;
|
std::vector<difficulty_type> difficulties;
|
||||||
uint64_t height;
|
uint64_t height;
|
||||||
top_hash = get_tail_id(height); // get it again now that we have the lock
|
auto new_top_hash = get_tail_id(height); // get it again now that we have the lock
|
||||||
++height; // top block height to blockchain height
|
++height;
|
||||||
|
|
||||||
uint8_t version = get_current_hard_fork_version();
|
uint8_t version = get_current_hard_fork_version();
|
||||||
uint64_t difficulty_blocks_count = version >= 11 ? DIFFICULTY_BLOCKS_COUNT_V3 : version <= 10 && version >= 8 ? DIFFICULTY_BLOCKS_COUNT_V2 : DIFFICULTY_BLOCKS_COUNT;
|
uint64_t difficulty_blocks_count = version >= 11 ? DIFFICULTY_BLOCKS_COUNT_V3 : version <= 10 && version >= 8 ? DIFFICULTY_BLOCKS_COUNT_V2 : DIFFICULTY_BLOCKS_COUNT;
|
||||||
|
if (!(new_top_hash == top_hash)) D=0;
|
||||||
|
ss << "Re-locked, height " << height << ", tail id " << new_top_hash << (new_top_hash == top_hash ? "" : " (different)") << std::endl;
|
||||||
|
top_hash = new_top_hash;
|
||||||
|
|
||||||
// ND: Speedup
|
// ND: Speedup
|
||||||
// 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
|
// 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
|
||||||
// then when the next block difficulty is queried, push the latest height data and
|
// then when the next block difficulty is queried, push the latest height data and
|
||||||
// pop the oldest one from the list. This only requires 1x read per height instead
|
// pop the oldest one from the list. This only requires 1x read per height instead
|
||||||
// of doing 735 (DIFFICULTY_BLOCKS_COUNT).
|
// of doing 735 (DIFFICULTY_BLOCKS_COUNT).
|
||||||
|
bool check = false;
|
||||||
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficulty_blocks_count)
|
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficulty_blocks_count)
|
||||||
{
|
{
|
||||||
uint64_t index = height - 1;
|
uint64_t index = height - 1;
|
||||||
|
@ -859,8 +874,12 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
m_timestamps_and_difficulties_height = height;
|
m_timestamps_and_difficulties_height = height;
|
||||||
timestamps = m_timestamps;
|
timestamps = m_timestamps;
|
||||||
difficulties = m_difficulties;
|
difficulties = m_difficulties;
|
||||||
|
check = true;
|
||||||
}
|
}
|
||||||
else
|
//else
|
||||||
|
std::vector<uint64_t> timestamps_from_cache = timestamps;
|
||||||
|
std::vector<difficulty_type> difficulties_from_cache = difficulties;
|
||||||
|
|
||||||
{
|
{
|
||||||
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(difficulty_blocks_count));
|
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(difficulty_blocks_count));
|
||||||
if (offset == 0)
|
if (offset == 0)
|
||||||
|
@ -873,16 +892,40 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
timestamps.reserve(height - offset);
|
timestamps.reserve(height - offset);
|
||||||
difficulties.reserve(height - offset);
|
difficulties.reserve(height - offset);
|
||||||
}
|
}
|
||||||
|
ss << "Looking up " << (height - offset) << " from " << offset << std::endl;
|
||||||
for (; offset < height; offset++)
|
for (; offset < height; offset++)
|
||||||
{
|
{
|
||||||
timestamps.push_back(m_db->get_block_timestamp(offset));
|
timestamps.push_back(m_db->get_block_timestamp(offset));
|
||||||
difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
|
difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check) if (timestamps != timestamps_from_cache || difficulties !=difficulties_from_cache)
|
||||||
|
{
|
||||||
|
ss << "Inconsistency XXX:" << std::endl;
|
||||||
|
ss << "top hash: "<<top_hash << std::endl;
|
||||||
|
ss << "timestamps: " << timestamps_from_cache.size() << " from cache, but " << timestamps.size() << " without" << std::endl;
|
||||||
|
ss << "difficulties: " << difficulties_from_cache.size() << " from cache, but " << difficulties.size() << " without" << std::endl;
|
||||||
|
ss << "timestamps_from_cache:" << std::endl; for (const auto &v :timestamps_from_cache) ss << " " << v << std::endl;
|
||||||
|
ss << "timestamps:" << std::endl; for (const auto &v :timestamps) ss << " " << v << std::endl;
|
||||||
|
ss << "difficulties_from_cache:" << std::endl; for (const auto &v :difficulties_from_cache) ss << " " << v << std::endl;
|
||||||
|
ss << "difficulties:" << std::endl; for (const auto &v :difficulties) ss << " " << v << std::endl;
|
||||||
|
|
||||||
|
uint64_t dbh = m_db->height();
|
||||||
|
uint64_t sh = dbh < 10000 ? 0 : dbh - 10000;
|
||||||
|
ss << "History from -10k at :" << dbh << ", from " << sh << std::endl;
|
||||||
|
for (uint64_t h = sh; h < dbh; ++h)
|
||||||
|
{
|
||||||
|
uint64_t ts = m_db->get_block_timestamp(h);
|
||||||
|
difficulty_type d = m_db->get_block_cumulative_difficulty(h);
|
||||||
|
ss << " " << h << " " << ts << " " << d << std::endl;
|
||||||
|
}
|
||||||
|
print = true;
|
||||||
|
}
|
||||||
m_timestamps_and_difficulties_height = height;
|
m_timestamps_and_difficulties_height = height;
|
||||||
m_timestamps = timestamps;
|
m_timestamps = timestamps;
|
||||||
m_difficulties = difficulties;
|
m_difficulties = difficulties;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t target = get_difficulty_target();
|
size_t target = get_difficulty_target();
|
||||||
uint64_t T = DIFFICULTY_TARGET_V2;
|
uint64_t T = DIFFICULTY_TARGET_V2;
|
||||||
uint64_t N = DIFFICULTY_WINDOW_V3;
|
uint64_t N = DIFFICULTY_WINDOW_V3;
|
||||||
|
@ -911,6 +954,28 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
CRITICAL_REGION_LOCAL1(m_difficulty_lock);
|
CRITICAL_REGION_LOCAL1(m_difficulty_lock);
|
||||||
m_difficulty_for_next_block_top_hash = top_hash;
|
m_difficulty_for_next_block_top_hash = top_hash;
|
||||||
m_difficulty_for_next_block = diff;
|
m_difficulty_for_next_block = diff;
|
||||||
|
if (D && D != diff)
|
||||||
|
{
|
||||||
|
ss << "XXX Mismatch at " << height << "/" << top_hash << "/" << get_tail_id() << ": cached " << D << ", real " << diff << std::endl;
|
||||||
|
print = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
++done;
|
||||||
|
if (done == 1 && D && D != diff)
|
||||||
|
{
|
||||||
|
print = true;
|
||||||
|
ss << "Might be a race. Let's see what happens if we try again..." << std::endl;
|
||||||
|
epee::misc_utils::sleep_no_w(100);
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
ss << "Diff for " << top_hash << ": " << diff << std::endl;
|
||||||
|
if (print)
|
||||||
|
{
|
||||||
|
MGINFO("START DUMP");
|
||||||
|
MGINFO(ss.str());
|
||||||
|
MGINFO("END DUMP");
|
||||||
|
MGINFO("Please send moneromooo on Freenode the contents of this log, from a couple dozen lines before START DUMP to END DUMP");
|
||||||
|
}
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
|
@ -1721,7 +1721,6 @@ namespace cryptonote
|
||||||
m_starter_message_showed = true;
|
m_starter_message_showed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fork_moaner.do_call(boost::bind(&core::check_fork_time, this));
|
|
||||||
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
|
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
|
||||||
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
|
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
|
||||||
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
|
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
|
||||||
|
@ -1732,29 +1731,6 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
bool core::check_fork_time()
|
|
||||||
{
|
|
||||||
if (m_nettype == FAKECHAIN)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
HardFork::State state = m_blockchain_storage.get_hard_fork_state();
|
|
||||||
el::Level level;
|
|
||||||
switch (state) {
|
|
||||||
case HardFork::LikelyForked:
|
|
||||||
level = el::Level::Warning;
|
|
||||||
MCLOG_RED(level, "global", "**********************************************************************");
|
|
||||||
MCLOG_RED(level, "global", "Last scheduled hard fork is too far in the past.");
|
|
||||||
MCLOG_RED(level, "global", "We are most likely forked from the network. Daemon update needed now.");
|
|
||||||
MCLOG_RED(level, "global", "**********************************************************************");
|
|
||||||
break;
|
|
||||||
case HardFork::UpdateNeeded:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------------------
|
|
||||||
uint8_t core::get_ideal_hard_fork_version() const
|
uint8_t core::get_ideal_hard_fork_version() const
|
||||||
{
|
{
|
||||||
return get_blockchain_storage().get_ideal_hard_fork_version();
|
return get_blockchain_storage().get_ideal_hard_fork_version();
|
||||||
|
|
|
@ -1000,18 +1000,6 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool check_tx_inputs_keyimages_domain(const transaction& tx) const;
|
bool check_tx_inputs_keyimages_domain(const transaction& tx) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief checks HardFork status and prints messages about it
|
|
||||||
*
|
|
||||||
* Checks the status of HardFork and logs/prints if an update to
|
|
||||||
* the daemon is necessary.
|
|
||||||
*
|
|
||||||
* @note see Blockchain::get_hard_fork_state and HardFork::State
|
|
||||||
*
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
bool check_fork_time();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief attempts to relay any transactions in the mempool which need it
|
* @brief attempts to relay any transactions in the mempool which need it
|
||||||
*
|
*
|
||||||
|
|
|
@ -51,7 +51,8 @@ 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
|
#define CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT 100
|
||||||
|
static_assert(CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT >= BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4, "Invalid CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT");
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
|
|
|
@ -308,9 +308,9 @@ namespace cryptonote
|
||||||
if (version >= 6 && version != hshd.top_version)
|
if (version >= 6 && version != hshd.top_version)
|
||||||
{
|
{
|
||||||
if (version < hshd.top_version && version == m_core.get_ideal_hard_fork_version())
|
if (version < hshd.top_version && version == m_core.get_ideal_hard_fork_version())
|
||||||
MCLOG_RED(el::Level::Warning, "global", context << " peer claims higher version than we think (" <<
|
MDEBUG(context << " peer claims higher version than we think (" <<
|
||||||
(unsigned)hshd.top_version << " for " << (hshd.current_height - 1) << " instead of " << (unsigned)version <<
|
(unsigned)hshd.top_version << " for " << (hshd.current_height - 1) << " instead of " << (unsigned)version <<
|
||||||
") - we may be forked from the network and a software upgrade may be needed");
|
") - we may be forked from the network and a software upgrade may be needed, or that peer is broken or malicious");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -793,6 +793,12 @@ namespace cryptonote
|
||||||
int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
|
int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
|
||||||
{
|
{
|
||||||
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes), block hash " << arg.block_hash);
|
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes), block hash " << arg.block_hash);
|
||||||
|
if (context.m_state == cryptonote_connection_context::state_before_handshake)
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("Requested fluffy tx before handshake, dropping connection");
|
||||||
|
drop_connection(context, false, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
|
std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
|
||||||
std::vector<cryptonote::blobdata> local_txs;
|
std::vector<cryptonote::blobdata> local_txs;
|
||||||
|
@ -884,6 +890,8 @@ namespace cryptonote
|
||||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_get_txpool_complement(int command, NOTIFY_GET_TXPOOL_COMPLEMENT::request& arg, cryptonote_connection_context& context)
|
int t_cryptonote_protocol_handler<t_core>::handle_notify_get_txpool_complement(int command, NOTIFY_GET_TXPOOL_COMPLEMENT::request& arg, cryptonote_connection_context& context)
|
||||||
{
|
{
|
||||||
MLOG_P2P_MESSAGE("Received NOTIFY_GET_TXPOOL_COMPLEMENT (" << arg.hashes.size() << " txes)");
|
MLOG_P2P_MESSAGE("Received NOTIFY_GET_TXPOOL_COMPLEMENT (" << arg.hashes.size() << " txes)");
|
||||||
|
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||||
|
return 1;
|
||||||
|
|
||||||
std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
|
std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
|
||||||
std::vector<cryptonote::blobdata> local_txs;
|
std::vector<cryptonote::blobdata> local_txs;
|
||||||
|
@ -987,6 +995,12 @@ namespace cryptonote
|
||||||
template<class t_core>
|
template<class t_core>
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
if (context.m_state == cryptonote_connection_context::state_before_handshake)
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("Requested objects before handshake, dropping connection");
|
||||||
|
drop_connection(context, false, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
|
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
|
||||||
if (arg.blocks.size() > CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT)
|
if (arg.blocks.size() > CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT)
|
||||||
{
|
{
|
||||||
|
@ -1717,11 +1731,16 @@ skip:
|
||||||
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
|
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
|
||||||
{
|
{
|
||||||
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
|
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
|
||||||
|
if (context.m_state == cryptonote_connection_context::state_before_handshake)
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("Requested chain before handshake, dropping connection");
|
||||||
|
drop_connection(context, false, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
|
NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
|
||||||
if(!m_core.find_blockchain_supplement(arg.block_ids, !arg.prune, r))
|
if(!m_core.find_blockchain_supplement(arg.block_ids, !arg.prune, r))
|
||||||
{
|
{
|
||||||
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
|
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
|
||||||
drop_connection(context, false, false);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
|
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
|
||||||
|
|
|
@ -1108,7 +1108,7 @@ namespace hw {
|
||||||
for(size_t n=0; n < additional_derivations.size();++n) {
|
for(size_t n=0; n < additional_derivations.size();++n) {
|
||||||
if(derivation == additional_derivations[n]) {
|
if(derivation == additional_derivations[n]) {
|
||||||
pkey = &additional_tx_pub_keys[n];
|
pkey = &additional_tx_pub_keys[n];
|
||||||
MDEBUG("conceal derivation with additionnal tx pub key");
|
MDEBUG("conceal derivation with additional tx pub key");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1640,20 +1640,20 @@ namespace hw {
|
||||||
|
|
||||||
//if (tx_version > 1)
|
//if (tx_version > 1)
|
||||||
{
|
{
|
||||||
ASSERT_X(recv_len>=32, "Not enought data from device");
|
ASSERT_X(recv_len>=32, "Not enough data from device");
|
||||||
crypto::secret_key scalar1;
|
crypto::secret_key scalar1;
|
||||||
this->receive_secret((unsigned char*)scalar1.data, offset);
|
this->receive_secret((unsigned char*)scalar1.data, offset);
|
||||||
amount_keys.push_back(rct::sk2rct(scalar1));
|
amount_keys.push_back(rct::sk2rct(scalar1));
|
||||||
recv_len -= 32;
|
recv_len -= 32;
|
||||||
}
|
}
|
||||||
ASSERT_X(recv_len>=32, "Not enought data from device");
|
ASSERT_X(recv_len>=32, "Not enough data from device");
|
||||||
memmove(out_eph_public_key.data, &this->buffer_recv[offset], 32);
|
memmove(out_eph_public_key.data, &this->buffer_recv[offset], 32);
|
||||||
recv_len -= 32;
|
recv_len -= 32;
|
||||||
offset += 32;
|
offset += 32;
|
||||||
|
|
||||||
if (need_additional_txkeys)
|
if (need_additional_txkeys)
|
||||||
{
|
{
|
||||||
ASSERT_X(recv_len>=32, "Not enought data from device");
|
ASSERT_X(recv_len>=32, "Not enough data from device");
|
||||||
memmove(additional_txkey.pub.data, &this->buffer_recv[offset], 32);
|
memmove(additional_txkey.pub.data, &this->buffer_recv[offset], 32);
|
||||||
additional_tx_public_keys.push_back(additional_txkey.pub);
|
additional_tx_public_keys.push_back(additional_txkey.pub);
|
||||||
offset += 32;
|
offset += 32;
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include "misc_log_ex.h"
|
#include "misc_log_ex.h"
|
||||||
#include "fnv1.h"
|
#include "fnv1.h"
|
||||||
|
#include "common/utf8.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \namespace Language
|
* \namespace Language
|
||||||
|
@ -73,78 +74,11 @@ namespace Language
|
||||||
return prefix;
|
return prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline T utf8canonical(const T &s)
|
|
||||||
{
|
|
||||||
T sc = "";
|
|
||||||
size_t avail = s.size();
|
|
||||||
const char *ptr = s.data();
|
|
||||||
wint_t cp = 0;
|
|
||||||
int bytes = 1;
|
|
||||||
char wbuf[8], *wptr;
|
|
||||||
while (avail--)
|
|
||||||
{
|
|
||||||
if ((*ptr & 0x80) == 0)
|
|
||||||
{
|
|
||||||
cp = *ptr++;
|
|
||||||
bytes = 1;
|
|
||||||
}
|
|
||||||
else if ((*ptr & 0xe0) == 0xc0)
|
|
||||||
{
|
|
||||||
if (avail < 1)
|
|
||||||
throw std::runtime_error("Invalid UTF-8");
|
|
||||||
cp = (*ptr++ & 0x1f) << 6;
|
|
||||||
cp |= *ptr++ & 0x3f;
|
|
||||||
--avail;
|
|
||||||
bytes = 2;
|
|
||||||
}
|
|
||||||
else if ((*ptr & 0xf0) == 0xe0)
|
|
||||||
{
|
|
||||||
if (avail < 2)
|
|
||||||
throw std::runtime_error("Invalid UTF-8");
|
|
||||||
cp = (*ptr++ & 0xf) << 12;
|
|
||||||
cp |= (*ptr++ & 0x3f) << 6;
|
|
||||||
cp |= *ptr++ & 0x3f;
|
|
||||||
avail -= 2;
|
|
||||||
bytes = 3;
|
|
||||||
}
|
|
||||||
else if ((*ptr & 0xf8) == 0xf0)
|
|
||||||
{
|
|
||||||
if (avail < 3)
|
|
||||||
throw std::runtime_error("Invalid UTF-8");
|
|
||||||
cp = (*ptr++ & 0x7) << 18;
|
|
||||||
cp |= (*ptr++ & 0x3f) << 12;
|
|
||||||
cp |= (*ptr++ & 0x3f) << 6;
|
|
||||||
cp |= *ptr++ & 0x3f;
|
|
||||||
avail -= 3;
|
|
||||||
bytes = 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw std::runtime_error("Invalid UTF-8");
|
|
||||||
|
|
||||||
cp = std::towlower(cp);
|
|
||||||
wptr = wbuf;
|
|
||||||
switch (bytes)
|
|
||||||
{
|
|
||||||
case 1: *wptr++ = cp; break;
|
|
||||||
case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
|
|
||||||
case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
|
|
||||||
case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
|
|
||||||
default: throw std::runtime_error("Invalid UTF-8");
|
|
||||||
}
|
|
||||||
*wptr = 0;
|
|
||||||
sc += T(wbuf, bytes);
|
|
||||||
cp = 0;
|
|
||||||
bytes = 1;
|
|
||||||
}
|
|
||||||
return sc;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WordHash
|
struct WordHash
|
||||||
{
|
{
|
||||||
std::size_t operator()(const epee::wipeable_string &s) const
|
std::size_t operator()(const epee::wipeable_string &s) const
|
||||||
{
|
{
|
||||||
const epee::wipeable_string sc = utf8canonical(s);
|
const epee::wipeable_string sc = tools::utf8canonical(s, [](wint_t c) -> wint_t { return std::towlower(c); });
|
||||||
return epee::fnv::FNV1a(sc.data(), sc.size());
|
return epee::fnv::FNV1a(sc.data(), sc.size());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -153,8 +87,8 @@ namespace Language
|
||||||
{
|
{
|
||||||
bool operator()(const epee::wipeable_string &s0, const epee::wipeable_string &s1) const
|
bool operator()(const epee::wipeable_string &s0, const epee::wipeable_string &s1) const
|
||||||
{
|
{
|
||||||
const epee::wipeable_string s0c = utf8canonical(s0);
|
const epee::wipeable_string s0c = tools::utf8canonical(s0, [](wint_t c) -> wint_t { return std::towlower(c); });
|
||||||
const epee::wipeable_string s1c = utf8canonical(s1);
|
const epee::wipeable_string s1c = tools::utf8canonical(s1, [](wint_t c) -> wint_t { return std::towlower(c); });
|
||||||
return s0c == s1c;
|
return s0c == s1c;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,6 +68,11 @@ using namespace epee;
|
||||||
#define DEFAULT_PAYMENT_DIFFICULTY 1000
|
#define DEFAULT_PAYMENT_DIFFICULTY 1000
|
||||||
#define DEFAULT_PAYMENT_CREDITS_PER_HASH 100
|
#define DEFAULT_PAYMENT_CREDITS_PER_HASH 100
|
||||||
|
|
||||||
|
#define RESTRICTED_BLOCK_HEADER_RANGE 1000
|
||||||
|
#define RESTRICTED_TRANSACTIONS_COUNT 100
|
||||||
|
#define RESTRICTED_SPENT_KEY_IMAGES_COUNT 5000
|
||||||
|
#define RESTRICTED_BLOCK_COUNT 1000
|
||||||
|
|
||||||
#define RPC_TRACKER(rpc) \
|
#define RPC_TRACKER(rpc) \
|
||||||
PERF_TIMER(rpc); \
|
PERF_TIMER(rpc); \
|
||||||
RPCTracker tracker(#rpc, PERF_TIMER_NAME(rpc))
|
RPCTracker tracker(#rpc, PERF_TIMER_NAME(rpc))
|
||||||
|
@ -639,6 +644,13 @@ namespace cryptonote
|
||||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
|
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
const bool restricted = m_restricted && ctx;
|
||||||
|
if (restricted && req.heights.size() > RESTRICTED_BLOCK_COUNT)
|
||||||
|
{
|
||||||
|
res.status = "Too many blocks requested in restricted mode";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
res.status = "Failed";
|
res.status = "Failed";
|
||||||
res.blocks.clear();
|
res.blocks.clear();
|
||||||
res.blocks.reserve(req.heights.size());
|
res.blocks.reserve(req.heights.size());
|
||||||
|
@ -793,11 +805,17 @@ namespace cryptonote
|
||||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
|
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
|
|
||||||
|
|
||||||
const bool restricted = m_restricted && ctx;
|
const bool restricted = m_restricted && ctx;
|
||||||
const bool request_has_rpc_origin = ctx != NULL;
|
const bool request_has_rpc_origin = ctx != NULL;
|
||||||
|
|
||||||
|
if (restricted && req.txs_hashes.size() > RESTRICTED_TRANSACTIONS_COUNT)
|
||||||
|
{
|
||||||
|
res.status = "Too many transactions requested in restricted mode";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
|
||||||
|
|
||||||
std::vector<crypto::hash> vh;
|
std::vector<crypto::hash> vh;
|
||||||
for(const auto& tx_hex_str: req.txs_hashes)
|
for(const auto& tx_hex_str: req.txs_hashes)
|
||||||
{
|
{
|
||||||
|
@ -1027,11 +1045,17 @@ namespace cryptonote
|
||||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
|
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
|
|
||||||
|
|
||||||
const bool restricted = m_restricted && ctx;
|
const bool restricted = m_restricted && ctx;
|
||||||
const bool request_has_rpc_origin = ctx != NULL;
|
const bool request_has_rpc_origin = ctx != NULL;
|
||||||
|
|
||||||
|
if (restricted && req.key_images.size() > RESTRICTED_SPENT_KEY_IMAGES_COUNT)
|
||||||
|
{
|
||||||
|
res.status = "Too many key images queried in restricted mode";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
|
||||||
|
|
||||||
std::vector<crypto::key_image> key_images;
|
std::vector<crypto::key_image> key_images;
|
||||||
for(const auto& ki_hex_str: req.key_images)
|
for(const auto& ki_hex_str: req.key_images)
|
||||||
{
|
{
|
||||||
|
@ -2035,6 +2059,14 @@ namespace cryptonote
|
||||||
|
|
||||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
|
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
|
||||||
|
|
||||||
|
const bool restricted = m_restricted && ctx;
|
||||||
|
if (restricted && req.hashes.size() > RESTRICTED_BLOCK_COUNT)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_RESTRICTED;
|
||||||
|
error_resp.message = "Too many block headers requested in restricted mode";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool {
|
auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool {
|
||||||
crypto::hash block_hash;
|
crypto::hash block_hash;
|
||||||
bool hash_parsed = parse_hash256(hash, block_hash);
|
bool hash_parsed = parse_hash256(hash, block_hash);
|
||||||
|
@ -2070,7 +2102,6 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool restricted = m_restricted && ctx;
|
|
||||||
if (!req.hash.empty())
|
if (!req.hash.empty())
|
||||||
{
|
{
|
||||||
if (!get(req.hash, req.fill_pow_hash, res.block_header, restricted, error_resp))
|
if (!get(req.hash, req.fill_pow_hash, res.block_header, restricted, error_resp))
|
||||||
|
@ -2102,6 +2133,14 @@ namespace cryptonote
|
||||||
error_resp.message = "Invalid start/end heights.";
|
error_resp.message = "Invalid start/end heights.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const bool restricted = m_restricted && ctx;
|
||||||
|
if (restricted && req.end_height - req.start_height > RESTRICTED_BLOCK_HEADER_RANGE)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_RESTRICTED;
|
||||||
|
error_resp.message = "Too many block headers requested.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false);
|
CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false);
|
||||||
for (uint64_t h = req.start_height; h <= req.end_height; ++h)
|
for (uint64_t h = req.start_height; h <= req.end_height; ++h)
|
||||||
{
|
{
|
||||||
|
@ -2128,7 +2167,6 @@ namespace cryptonote
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
res.headers.push_back(block_header_response());
|
res.headers.push_back(block_header_response());
|
||||||
const bool restricted = m_restricted && ctx;
|
|
||||||
bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.headers.back(), req.fill_pow_hash && !restricted);
|
bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.headers.back(), req.fill_pow_hash && !restricted);
|
||||||
if (!response_filled)
|
if (!response_filled)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#define CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW -16
|
#define CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW -16
|
||||||
#define CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT -17
|
#define CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT -17
|
||||||
#define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18
|
#define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18
|
||||||
|
#define CORE_RPC_ERROR_CODE_RESTRICTED -19
|
||||||
|
|
||||||
static inline const char *get_rpc_server_error_message(int64_t code)
|
static inline const char *get_rpc_server_error_message(int64_t code)
|
||||||
{
|
{
|
||||||
|
@ -70,6 +71,7 @@ static inline const char *get_rpc_server_error_message(int64_t code)
|
||||||
case CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW: return "Payment too low";
|
case CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW: return "Payment too low";
|
||||||
case CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT: return "Duplicate payment";
|
case CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT: return "Duplicate payment";
|
||||||
case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment";
|
case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment";
|
||||||
|
case CORE_RPC_ERROR_CODE_RESTRICTED: return "Parameters beyond restricted allowance";
|
||||||
default: MERROR("Unknown error: " << code); return "Unknown error";
|
default: MERROR("Unknown error: " << code); return "Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ namespace cryptonote
|
||||||
|
|
||||||
uint64_t rpc_payment::balance(const crypto::public_key &client, int64_t delta)
|
uint64_t rpc_payment::balance(const crypto::public_key &client, int64_t delta)
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
client_info &info = m_client_info[client]; // creates if not found
|
client_info &info = m_client_info[client]; // creates if not found
|
||||||
uint64_t credits = info.credits;
|
uint64_t credits = info.credits;
|
||||||
if (delta > 0 && credits > std::numeric_limits<uint64_t>::max() - delta)
|
if (delta > 0 && credits > std::numeric_limits<uint64_t>::max() - delta)
|
||||||
|
@ -107,6 +108,7 @@ namespace cryptonote
|
||||||
|
|
||||||
bool rpc_payment::pay(const crypto::public_key &client, uint64_t ts, uint64_t payment, const std::string &rpc, bool same_ts, uint64_t &credits)
|
bool rpc_payment::pay(const crypto::public_key &client, uint64_t ts, uint64_t payment, const std::string &rpc, bool same_ts, uint64_t &credits)
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
client_info &info = m_client_info[client]; // creates if not found
|
client_info &info = m_client_info[client]; // creates if not found
|
||||||
if (ts < info.last_request_timestamp || (ts == info.last_request_timestamp && !same_ts))
|
if (ts < info.last_request_timestamp || (ts == info.last_request_timestamp && !same_ts))
|
||||||
{
|
{
|
||||||
|
@ -130,6 +132,7 @@ namespace cryptonote
|
||||||
|
|
||||||
bool rpc_payment::get_info(const crypto::public_key &client, const std::function<bool(const cryptonote::blobdata&, cryptonote::block&, uint64_t &seed_height, crypto::hash &seed_hash)> &get_block_template, cryptonote::blobdata &hashing_blob, uint64_t &seed_height, crypto::hash &seed_hash, const crypto::hash &top, uint64_t &diff, uint64_t &credits_per_hash_found, uint64_t &credits, uint32_t &cookie)
|
bool rpc_payment::get_info(const crypto::public_key &client, const std::function<bool(const cryptonote::blobdata&, cryptonote::block&, uint64_t &seed_height, crypto::hash &seed_hash)> &get_block_template, cryptonote::blobdata &hashing_blob, uint64_t &seed_height, crypto::hash &seed_hash, const crypto::hash &top, uint64_t &diff, uint64_t &credits_per_hash_found, uint64_t &credits, uint32_t &cookie)
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
client_info &info = m_client_info[client]; // creates if not found
|
client_info &info = m_client_info[client]; // creates if not found
|
||||||
const uint64_t now = time(NULL);
|
const uint64_t now = time(NULL);
|
||||||
bool need_template = top != info.top || now >= info.block_template_update_time + STALE_THRESHOLD;
|
bool need_template = top != info.top || now >= info.block_template_update_time + STALE_THRESHOLD;
|
||||||
|
@ -180,6 +183,7 @@ namespace cryptonote
|
||||||
|
|
||||||
bool rpc_payment::submit_nonce(const crypto::public_key &client, uint64_t nonce, const crypto::hash &top, int64_t &error_code, std::string &error_message, uint64_t &credits, crypto::hash &hash, cryptonote::block &block, uint32_t cookie, bool &stale)
|
bool rpc_payment::submit_nonce(const crypto::public_key &client, uint64_t nonce, const crypto::hash &top, int64_t &error_code, std::string &error_message, uint64_t &credits, crypto::hash &hash, cryptonote::block &block, uint32_t cookie, bool &stale)
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
client_info &info = m_client_info[client]; // creates if not found
|
client_info &info = m_client_info[client]; // creates if not found
|
||||||
if (cookie != info.cookie && cookie != info.cookie - 1)
|
if (cookie != info.cookie && cookie != info.cookie - 1)
|
||||||
{
|
{
|
||||||
|
@ -272,6 +276,7 @@ namespace cryptonote
|
||||||
|
|
||||||
bool rpc_payment::foreach(const std::function<bool(const crypto::public_key &client, const client_info &info)> &f) const
|
bool rpc_payment::foreach(const std::function<bool(const crypto::public_key &client, const client_info &info)> &f) const
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
for (std::unordered_map<crypto::public_key, client_info>::const_iterator i = m_client_info.begin(); i != m_client_info.end(); ++i)
|
for (std::unordered_map<crypto::public_key, client_info>::const_iterator i = m_client_info.begin(); i != m_client_info.end(); ++i)
|
||||||
{
|
{
|
||||||
if (!f(i->first, i->second))
|
if (!f(i->first, i->second))
|
||||||
|
@ -283,6 +288,7 @@ namespace cryptonote
|
||||||
bool rpc_payment::load(std::string directory)
|
bool rpc_payment::load(std::string directory)
|
||||||
{
|
{
|
||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
m_directory = std::move(directory);
|
m_directory = std::move(directory);
|
||||||
std::string state_file_path = directory + "/" + RPC_PAYMENTS_DATA_FILENAME;
|
std::string state_file_path = directory + "/" + RPC_PAYMENTS_DATA_FILENAME;
|
||||||
MINFO("loading rpc payments data from " << state_file_path);
|
MINFO("loading rpc payments data from " << state_file_path);
|
||||||
|
@ -313,6 +319,7 @@ namespace cryptonote
|
||||||
bool rpc_payment::store(const std::string &directory_) const
|
bool rpc_payment::store(const std::string &directory_) const
|
||||||
{
|
{
|
||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
const std::string &directory = directory_.empty() ? m_directory : directory_;
|
const std::string &directory = directory_.empty() ? m_directory : directory_;
|
||||||
MDEBUG("storing rpc payments data to " << directory);
|
MDEBUG("storing rpc payments data to " << directory);
|
||||||
if (!tools::create_directories_if_necessary(directory))
|
if (!tools::create_directories_if_necessary(directory))
|
||||||
|
@ -345,6 +352,7 @@ namespace cryptonote
|
||||||
|
|
||||||
unsigned int rpc_payment::flush_by_age(time_t seconds)
|
unsigned int rpc_payment::flush_by_age(time_t seconds)
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
const time_t now = time(NULL);
|
const time_t now = time(NULL);
|
||||||
time_t seconds0 = seconds;
|
time_t seconds0 = seconds;
|
||||||
|
@ -372,6 +380,7 @@ namespace cryptonote
|
||||||
|
|
||||||
uint64_t rpc_payment::get_hashes(unsigned int seconds) const
|
uint64_t rpc_payment::get_hashes(unsigned int seconds) const
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
const uint64_t now = time(NULL);
|
const uint64_t now = time(NULL);
|
||||||
uint64_t hashes = 0;
|
uint64_t hashes = 0;
|
||||||
for (std::map<uint64_t, uint64_t>::const_reverse_iterator i = m_hashrate.crbegin(); i != m_hashrate.crend(); ++i)
|
for (std::map<uint64_t, uint64_t>::const_reverse_iterator i = m_hashrate.crbegin(); i != m_hashrate.crend(); ++i)
|
||||||
|
@ -385,6 +394,7 @@ namespace cryptonote
|
||||||
|
|
||||||
void rpc_payment::prune_hashrate(unsigned int seconds)
|
void rpc_payment::prune_hashrate(unsigned int seconds)
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::mutex> lock(mutex);
|
||||||
const uint64_t now = time(NULL);
|
const uint64_t now = time(NULL);
|
||||||
std::map<uint64_t, uint64_t>::iterator i;
|
std::map<uint64_t, uint64_t>::iterator i;
|
||||||
for (i = m_hashrate.begin(); i != m_hashrate.end(); ++i)
|
for (i = m_hashrate.begin(); i != m_hashrate.end(); ++i)
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/serialization/version.hpp>
|
#include <boost/serialization/version.hpp>
|
||||||
#include "cryptonote_basic/blobdatatype.h"
|
#include "cryptonote_basic/blobdatatype.h"
|
||||||
#include "cryptonote_basic/cryptonote_basic.h"
|
#include "cryptonote_basic/cryptonote_basic.h"
|
||||||
|
@ -139,6 +140,7 @@ namespace cryptonote
|
||||||
uint64_t m_nonces_stale;
|
uint64_t m_nonces_stale;
|
||||||
uint64_t m_nonces_bad;
|
uint64_t m_nonces_bad;
|
||||||
uint64_t m_nonces_dupe;
|
uint64_t m_nonces_dupe;
|
||||||
|
mutable boost::mutex mutex;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ void read_hex(const rapidjson::Value& val, epee::span<std::uint8_t> dest)
|
||||||
throw WRONG_TYPE("string");
|
throw WRONG_TYPE("string");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!epee::from_hex::to_buffer(dest, {val.GetString(), val.Size()}))
|
if (!epee::from_hex::to_buffer(dest, {val.GetString(), val.GetStringLength()}))
|
||||||
{
|
{
|
||||||
throw BAD_INPUT();
|
throw BAD_INPUT();
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,6 +255,7 @@ namespace
|
||||||
const char* USAGE_MMS_SET("mms set <option_name> [<option_value>]");
|
const char* USAGE_MMS_SET("mms set <option_name> [<option_value>]");
|
||||||
const char* USAGE_MMS_SEND_SIGNER_CONFIG("mms send_signer_config");
|
const char* USAGE_MMS_SEND_SIGNER_CONFIG("mms send_signer_config");
|
||||||
const char* USAGE_MMS_START_AUTO_CONFIG("mms start_auto_config [<label> <label> ...]");
|
const char* USAGE_MMS_START_AUTO_CONFIG("mms start_auto_config [<label> <label> ...]");
|
||||||
|
const char* USAGE_MMS_CONFIG_CHECKSUM("mms config_checksum");
|
||||||
const char* USAGE_MMS_STOP_AUTO_CONFIG("mms stop_auto_config");
|
const char* USAGE_MMS_STOP_AUTO_CONFIG("mms stop_auto_config");
|
||||||
const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
|
const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
|
||||||
const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
|
const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
|
||||||
|
@ -3465,8 +3466,8 @@ simple_wallet::simple_wallet()
|
||||||
tr("Interface with the MMS (Multisig Messaging System)\n"
|
tr("Interface with the MMS (Multisig Messaging System)\n"
|
||||||
"<subcommand> is one of:\n"
|
"<subcommand> is one of:\n"
|
||||||
" init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n"
|
" init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n"
|
||||||
" send_signer_config, start_auto_config, stop_auto_config, auto_config\n"
|
" send_signer_config, start_auto_config, stop_auto_config, auto_config, config_checksum\n"
|
||||||
"Get help about a subcommand with: help_advanced mms <subcommand>"));
|
"Get help about a subcommand with: help_advanced mms <subcommand>, or mms help <subcommand>"));
|
||||||
m_cmd_binder.set_handler("mms init",
|
m_cmd_binder.set_handler("mms init",
|
||||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
|
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
|
||||||
tr(USAGE_MMS_INIT),
|
tr(USAGE_MMS_INIT),
|
||||||
|
@ -3534,6 +3535,10 @@ simple_wallet::simple_wallet()
|
||||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
|
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
|
||||||
tr(USAGE_MMS_START_AUTO_CONFIG),
|
tr(USAGE_MMS_START_AUTO_CONFIG),
|
||||||
tr("Start auto-config at the auto-config manager's wallet by issuing auto-config tokens and optionally set others' labels"));
|
tr("Start auto-config at the auto-config manager's wallet by issuing auto-config tokens and optionally set others' labels"));
|
||||||
|
m_cmd_binder.set_handler("mms config_checksum",
|
||||||
|
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
|
||||||
|
tr(USAGE_MMS_CONFIG_CHECKSUM),
|
||||||
|
tr("Get a checksum that allows signers to easily check for identical MMS configuration"));
|
||||||
m_cmd_binder.set_handler("mms stop_auto_config",
|
m_cmd_binder.set_handler("mms stop_auto_config",
|
||||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
|
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
|
||||||
tr(USAGE_MMS_STOP_AUTO_CONFIG),
|
tr(USAGE_MMS_STOP_AUTO_CONFIG),
|
||||||
|
@ -10379,6 +10384,14 @@ bool simple_wallet::user_confirms(const std::string &question)
|
||||||
return !std::cin.eof() && command_line::is_yes(answer);
|
return !std::cin.eof() && command_line::is_yes(answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool simple_wallet::user_confirms_auto_config()
|
||||||
|
{
|
||||||
|
message_writer(console_color_red, true) << tr("WARNING: Using MMS auto-config mechanisms is not trustless");
|
||||||
|
message_writer() << tr("A malicious auto-config manager could send you info about own wallets instead of other signers' info");
|
||||||
|
message_writer() << tr("If in doubt do not use auto-config or at least compare configs using the \"mms config_checksum\" command");
|
||||||
|
return user_confirms("Accept the risks and continue?");
|
||||||
|
}
|
||||||
|
|
||||||
bool simple_wallet::get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound)
|
bool simple_wallet::get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound)
|
||||||
{
|
{
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
@ -10531,7 +10544,7 @@ void simple_wallet::show_message(const mms::message &m)
|
||||||
case mms::message_type::additional_key_set:
|
case mms::message_type::additional_key_set:
|
||||||
case mms::message_type::note:
|
case mms::message_type::note:
|
||||||
display_content = true;
|
display_content = true;
|
||||||
ms.get_sanitized_message_text(m, sanitized_text);
|
ms.get_sanitized_text(m.content, 1000, sanitized_text);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
display_content = false;
|
display_content = false;
|
||||||
|
@ -10880,6 +10893,11 @@ void simple_wallet::mms_next(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!user_confirms_auto_config())
|
||||||
|
{
|
||||||
|
message_writer() << tr("You can use the \"mms delete\" command to delete any unwanted message");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ms.process_signer_config(state, m.content);
|
ms.process_signer_config(state, m.content);
|
||||||
ms.stop_auto_config();
|
ms.stop_auto_config();
|
||||||
|
@ -11206,6 +11224,18 @@ void simple_wallet::mms_start_auto_config(const std::vector<std::string> &args)
|
||||||
list_signers(ms.get_all_signers());
|
list_signers(ms.get_all_signers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simple_wallet::mms_config_checksum(const std::vector<std::string> &args)
|
||||||
|
{
|
||||||
|
if (args.size() != 0)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Usage: mms config_checksum");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mms::message_store& ms = m_wallet->get_message_store();
|
||||||
|
LOCK_IDLE_SCOPE();
|
||||||
|
message_writer() << ms.get_config_checksum();
|
||||||
|
}
|
||||||
|
|
||||||
void simple_wallet::mms_stop_auto_config(const std::vector<std::string> &args)
|
void simple_wallet::mms_stop_auto_config(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
if (args.size() != 0)
|
if (args.size() != 0)
|
||||||
|
@ -11236,6 +11266,10 @@ void simple_wallet::mms_auto_config(const std::vector<std::string> &args)
|
||||||
fail_msg_writer() << tr("Invalid auto-config token");
|
fail_msg_writer() << tr("Invalid auto-config token");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!user_confirms_auto_config())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
mms::authorized_signer me = ms.get_signer(0);
|
mms::authorized_signer me = ms.get_signer(0);
|
||||||
if (me.auto_config_running)
|
if (me.auto_config_running)
|
||||||
{
|
{
|
||||||
|
@ -11348,6 +11382,10 @@ bool simple_wallet::mms(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
mms_start_auto_config(mms_args);
|
mms_start_auto_config(mms_args);
|
||||||
}
|
}
|
||||||
|
else if (sub_command == "config_checksum")
|
||||||
|
{
|
||||||
|
mms_config_checksum(mms_args);
|
||||||
|
}
|
||||||
else if (sub_command == "stop_auto_config")
|
else if (sub_command == "stop_auto_config")
|
||||||
{
|
{
|
||||||
mms_stop_auto_config(mms_args);
|
mms_stop_auto_config(mms_args);
|
||||||
|
|
|
@ -478,6 +478,7 @@ namespace cryptonote
|
||||||
void ask_send_all_ready_messages();
|
void ask_send_all_ready_messages();
|
||||||
void check_for_messages();
|
void check_for_messages();
|
||||||
bool user_confirms(const std::string &question);
|
bool user_confirms(const std::string &question);
|
||||||
|
bool user_confirms_auto_config();
|
||||||
bool get_message_from_arg(const std::string &arg, mms::message &m);
|
bool get_message_from_arg(const std::string &arg, mms::message &m);
|
||||||
bool get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound);
|
bool get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound);
|
||||||
|
|
||||||
|
@ -498,6 +499,7 @@ namespace cryptonote
|
||||||
void mms_help(const std::vector<std::string> &args);
|
void mms_help(const std::vector<std::string> &args);
|
||||||
void mms_send_signer_config(const std::vector<std::string> &args);
|
void mms_send_signer_config(const std::vector<std::string> &args);
|
||||||
void mms_start_auto_config(const std::vector<std::string> &args);
|
void mms_start_auto_config(const std::vector<std::string> &args);
|
||||||
|
void mms_config_checksum(const std::vector<std::string> &args);
|
||||||
void mms_stop_auto_config(const std::vector<std::string> &args);
|
void mms_stop_auto_config(const std::vector<std::string> &args);
|
||||||
void mms_auto_config(const std::vector<std::string> &args);
|
void mms_auto_config(const std::vector<std::string> &args);
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "serialization/binary_utils.h"
|
#include "serialization/binary_utils.h"
|
||||||
#include "common/base58.h"
|
#include "common/base58.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
#include "common/utf8.h"
|
||||||
#include "string_tools.h"
|
#include "string_tools.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,18 +130,18 @@ void message_store::set_signer(const multisig_wallet_state &state,
|
||||||
authorized_signer &m = m_signers[index];
|
authorized_signer &m = m_signers[index];
|
||||||
if (label)
|
if (label)
|
||||||
{
|
{
|
||||||
m.label = label.get();
|
get_sanitized_text(label.get(), 50, m.label);
|
||||||
}
|
}
|
||||||
if (transport_address)
|
if (transport_address)
|
||||||
{
|
{
|
||||||
m.transport_address = transport_address.get();
|
get_sanitized_text(transport_address.get(), 200, m.transport_address);
|
||||||
}
|
}
|
||||||
if (monero_address)
|
if (monero_address)
|
||||||
{
|
{
|
||||||
m.monero_address_known = true;
|
m.monero_address_known = true;
|
||||||
m.monero_address = monero_address.get();
|
m.monero_address = monero_address.get();
|
||||||
}
|
}
|
||||||
// Save to minimize the chance to loose that info (at least while in beta)
|
// Save to minimize the chance to loose that info
|
||||||
save(state);
|
save(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +203,17 @@ void message_store::unpack_signer_config(const multisig_wallet_state &state, con
|
||||||
}
|
}
|
||||||
uint32_t num_signers = (uint32_t)signers.size();
|
uint32_t num_signers = (uint32_t)signers.size();
|
||||||
THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + std::to_string(num_signers));
|
THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + std::to_string(num_signers));
|
||||||
|
for (uint32_t i = 0; i < num_signers; ++i)
|
||||||
|
{
|
||||||
|
authorized_signer &m = signers[i];
|
||||||
|
std::string temp;
|
||||||
|
get_sanitized_text(m.label, 50, temp);
|
||||||
|
m.label = temp;
|
||||||
|
get_sanitized_text(m.transport_address, 200, temp);
|
||||||
|
m.transport_address = temp;
|
||||||
|
get_sanitized_text(m.auto_config_token, 20, temp);
|
||||||
|
m.auto_config_token = temp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void message_store::process_signer_config(const multisig_wallet_state &state, const std::string &signer_config)
|
void message_store::process_signer_config(const multisig_wallet_state &state, const std::string &signer_config)
|
||||||
|
@ -242,10 +254,10 @@ void message_store::process_signer_config(const multisig_wallet_state &state, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
authorized_signer &modify = m_signers[take_index];
|
authorized_signer &modify = m_signers[take_index];
|
||||||
modify.label = m.label; // ALWAYS set label, see comments above
|
get_sanitized_text(m.label, 50, modify.label); // ALWAYS set label, see comments above
|
||||||
if (!modify.me)
|
if (!modify.me)
|
||||||
{
|
{
|
||||||
modify.transport_address = m.transport_address;
|
get_sanitized_text(m.transport_address, 200, modify.transport_address);
|
||||||
modify.monero_address_known = m.monero_address_known;
|
modify.monero_address_known = m.monero_address_known;
|
||||||
if (m.monero_address_known)
|
if (m.monero_address_known)
|
||||||
{
|
{
|
||||||
|
@ -392,6 +404,45 @@ void message_store::process_auto_config_data_message(uint32_t id)
|
||||||
signer.auto_config_running = false;
|
signer.auto_config_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_hash(crypto::hash &sum, const crypto::hash &summand)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < crypto::HASH_SIZE; ++i)
|
||||||
|
{
|
||||||
|
uint32_t x = (uint32_t)sum.data[i];
|
||||||
|
uint32_t y = (uint32_t)summand.data[i];
|
||||||
|
sum.data[i] = (char)((x + y) % 256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate a checksum that allows signers to make sure they work with an identical signer config
|
||||||
|
// by exchanging and comparing checksums out-of-band i.e. not using the MMS;
|
||||||
|
// Because different signers have a different order of signers in the config work with "adding"
|
||||||
|
// individual hashes because that operation is commutative
|
||||||
|
std::string message_store::get_config_checksum() const
|
||||||
|
{
|
||||||
|
crypto::hash sum = crypto::null_hash;
|
||||||
|
uint32_t num = SWAP32LE(m_num_authorized_signers);
|
||||||
|
add_hash(sum, crypto::cn_fast_hash(&num, sizeof(num)));
|
||||||
|
num = SWAP32LE(m_num_required_signers);
|
||||||
|
add_hash(sum, crypto::cn_fast_hash(&num, sizeof(num)));
|
||||||
|
for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
|
||||||
|
{
|
||||||
|
const authorized_signer &m = m_signers[i];
|
||||||
|
add_hash(sum, crypto::cn_fast_hash(m.transport_address.data(), m.transport_address.size()));
|
||||||
|
if (m.monero_address_known)
|
||||||
|
{
|
||||||
|
add_hash(sum, crypto::cn_fast_hash(&m.monero_address.m_spend_public_key, sizeof(m.monero_address.m_spend_public_key)));
|
||||||
|
add_hash(sum, crypto::cn_fast_hash(&m.monero_address.m_view_public_key, sizeof(m.monero_address.m_view_public_key)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string checksum_bytes;
|
||||||
|
checksum_bytes += sum.data[0];
|
||||||
|
checksum_bytes += sum.data[1];
|
||||||
|
checksum_bytes += sum.data[2];
|
||||||
|
checksum_bytes += sum.data[3];
|
||||||
|
return epee::string_tools::buff_to_hex_nodelimer(checksum_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
void message_store::stop_auto_config()
|
void message_store::stop_auto_config()
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
|
for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
|
||||||
|
@ -661,31 +712,36 @@ void message_store::delete_all_messages()
|
||||||
m_messages.clear();
|
m_messages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a message text, which is "attacker controlled data", reasonably safe to display
|
// Make a text, which is "attacker controlled data", reasonably safe to display
|
||||||
// This is mostly geared towards the safe display of notes sent by "mms note" with a "mms show" command
|
// This is mostly geared towards the safe display of notes sent by "mms note" with a "mms show" command
|
||||||
void message_store::get_sanitized_message_text(const message &m, std::string &sanitized_text) const
|
void message_store::get_sanitized_text(const std::string &text, size_t max_length, std::string &sanitized_text) const
|
||||||
{
|
{
|
||||||
sanitized_text.clear();
|
|
||||||
|
|
||||||
// Restrict the size to fend of DOS-style attacks with heaps of data
|
// Restrict the size to fend of DOS-style attacks with heaps of data
|
||||||
size_t length = std::min(m.content.length(), (size_t)1000);
|
size_t length = std::min(text.length(), max_length);
|
||||||
|
sanitized_text = text.substr(0, length);
|
||||||
|
|
||||||
for (size_t i = 0; i < length; ++i)
|
try
|
||||||
{
|
{
|
||||||
char c = m.content[i];
|
sanitized_text = tools::utf8canonical(sanitized_text, [](wint_t c)
|
||||||
if ((int)c < 32)
|
|
||||||
{
|
{
|
||||||
// Strip out any controls, especially ESC for getting rid of potentially dangerous
|
if ((c < 0x20) || (c == 0x7f) || (c >= 0x80 && c <= 0x9f))
|
||||||
// ANSI escape sequences that a console window might interpret
|
{
|
||||||
c = ' ';
|
// Strip out any controls, especially ESC for getting rid of potentially dangerous
|
||||||
}
|
// ANSI escape sequences that a console window might interpret
|
||||||
else if ((c == '<') || (c == '>'))
|
c = '?';
|
||||||
{
|
}
|
||||||
// Make XML or HTML impossible that e.g. might contain scripts that Qt might execute
|
else if ((c == '<') || (c == '>'))
|
||||||
// when displayed in the GUI wallet
|
{
|
||||||
c = ' ';
|
// Make XML or HTML impossible that e.g. might contain scripts that Qt might execute
|
||||||
}
|
// when displayed in the GUI wallet
|
||||||
sanitized_text += c;
|
c = '?';
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
sanitized_text = "(Illegal UTF-8 string)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -242,6 +242,7 @@ namespace mms
|
||||||
size_t add_auto_config_data_message(const multisig_wallet_state &state,
|
size_t add_auto_config_data_message(const multisig_wallet_state &state,
|
||||||
const std::string &auto_config_token);
|
const std::string &auto_config_token);
|
||||||
void process_auto_config_data_message(uint32_t id);
|
void process_auto_config_data_message(uint32_t id);
|
||||||
|
std::string get_config_checksum() const;
|
||||||
void stop_auto_config();
|
void stop_auto_config();
|
||||||
|
|
||||||
// Process data just created by "me" i.e. the own local wallet, e.g. as the result of a "prepare_multisig" command
|
// Process data just created by "me" i.e. the own local wallet, e.g. as the result of a "prepare_multisig" command
|
||||||
|
@ -275,7 +276,7 @@ namespace mms
|
||||||
void set_message_processed_or_sent(uint32_t id);
|
void set_message_processed_or_sent(uint32_t id);
|
||||||
void delete_message(uint32_t id);
|
void delete_message(uint32_t id);
|
||||||
void delete_all_messages();
|
void delete_all_messages();
|
||||||
void get_sanitized_message_text(const message &m, std::string &sanitized_text) const;
|
void get_sanitized_text(const std::string &text, size_t max_length, std::string &sanitized_text) const;
|
||||||
|
|
||||||
void send_message(const multisig_wallet_state &state, uint32_t id);
|
void send_message(const multisig_wallet_state &state, uint32_t id);
|
||||||
bool check_for_messages(const multisig_wallet_state &state, std::vector<message> &messages);
|
bool check_for_messages(const multisig_wallet_state &state, std::vector<message> &messages);
|
||||||
|
|
|
@ -13083,7 +13083,7 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs)
|
||||||
CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources");
|
CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources");
|
||||||
|
|
||||||
std::vector<std::vector<rct::key>> k;
|
std::vector<std::vector<rct::key>> k;
|
||||||
auto wiper = epee::misc_utils::create_scope_leave_handler([&](){memwipe(k.data(), k.size() * sizeof(k[0]));});
|
auto wiper = epee::misc_utils::create_scope_leave_handler([&](){for (auto &v: k) memwipe(v.data(), v.size() * sizeof(v[0]));});
|
||||||
k.reserve(m_transfers.size());
|
k.reserve(m_transfers.size());
|
||||||
for (const auto &td: m_transfers)
|
for (const auto &td: m_transfers)
|
||||||
k.push_back(td.m_multisig_k);
|
k.push_back(td.m_multisig_k);
|
||||||
|
|
|
@ -387,6 +387,29 @@ TEST(ByteSlice, Construction)
|
||||||
EXPECT_FALSE(std::is_copy_assignable<epee::byte_slice>());
|
EXPECT_FALSE(std::is_copy_assignable<epee::byte_slice>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ByteSlice, DataReturnedMatches)
|
||||||
|
{
|
||||||
|
for (int i = 64; i > 0; i--)
|
||||||
|
{
|
||||||
|
std::string sso_string(i, 'a');
|
||||||
|
std::string original = sso_string;
|
||||||
|
epee::byte_slice slice{std::move(sso_string)};
|
||||||
|
|
||||||
|
EXPECT_EQ(slice.size(), original.size());
|
||||||
|
EXPECT_EQ(memcmp(slice.data(), original.data(), original.size()), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 64; i > 0; i--)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sso_vector(i, 'a');
|
||||||
|
std::vector<uint8_t> original = sso_vector;
|
||||||
|
epee::byte_slice slice{std::move(sso_vector)};
|
||||||
|
|
||||||
|
EXPECT_EQ(slice.size(), original.size());
|
||||||
|
EXPECT_EQ(memcmp(slice.data(), original.data(), original.size()), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ByteSlice, NoExcept)
|
TEST(ByteSlice, NoExcept)
|
||||||
{
|
{
|
||||||
EXPECT_TRUE(std::is_nothrow_default_constructible<epee::byte_slice>());
|
EXPECT_TRUE(std::is_nothrow_default_constructible<epee::byte_slice>());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue