mirror of
https://github.com/monero-project/monero.git
synced 2025-12-09 22:30:52 -08:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3942a1cd04 | ||
|
|
e4c0cb0ff3 | ||
|
|
9d7f473af0 | ||
|
|
41652c9aa1 | ||
|
|
0a0ceb62f0 | ||
|
|
8e7b762092 | ||
|
|
551e6c9168 | ||
|
|
c09d142972 | ||
|
|
efca5b8af9 | ||
|
|
251c64f195 | ||
|
|
5bb83ab042 | ||
|
|
af4fb4729e | ||
|
|
8e829e034f | ||
|
|
398e64ccbe | ||
|
|
f690e4984d | ||
|
|
ebc9197326 | ||
|
|
81f9fa947b | ||
|
|
752837b2c8 | ||
|
|
981e0b5cc3 | ||
|
|
6f48a146f8 | ||
|
|
1a3bef15b9 | ||
|
|
44c93bb47a | ||
|
|
c3fc96f0cf | ||
|
|
07f6ecd227 | ||
|
|
4985afddb3 | ||
|
|
4191dc8981 | ||
|
|
32581fb223 | ||
|
|
f3dd25c0e0 | ||
|
|
33dc825d6f | ||
|
|
91f1be9ea2 | ||
|
|
35186b1b84 | ||
|
|
bddd5653e1 | ||
|
|
b36c4f354b | ||
|
|
1ba4c8dbc2 | ||
|
|
92d19c48da | ||
|
|
01606ee52e | ||
|
|
81d2389c24 | ||
|
|
ef64c4e22f | ||
|
|
7fa01f342c | ||
|
|
4603ec9765 | ||
|
|
0be71bcea9 | ||
|
|
1a627e1f89 | ||
|
|
c1229a4432 | ||
|
|
9f68111b69 | ||
|
|
d1e79f2086 | ||
|
|
8965489acb | ||
|
|
d6953406c9 | ||
|
|
5090cdc9f5 | ||
|
|
df1061c87d | ||
|
|
f55f3fe81c | ||
|
|
9b7ed2fd8b | ||
|
|
e8468c5dcf | ||
|
|
76cc82c292 | ||
|
|
81a23c73d2 | ||
|
|
4b86583492 | ||
|
|
30918a27ab | ||
|
|
940b042e28 | ||
|
|
c028f4c4d8 | ||
|
|
f9a9d2ee28 | ||
|
|
81aaa4ec7b | ||
|
|
6e594e53bb | ||
|
|
e88b9170db | ||
|
|
39e30d5481 | ||
|
|
1120df3c53 | ||
|
|
42403c7acc | ||
|
|
fa63d4b3f0 | ||
|
|
4d855fcca7 | ||
|
|
8ae0110d54 | ||
|
|
a9178e3584 | ||
|
|
bbe6ee39e5 | ||
|
|
94a86cf855 | ||
|
|
745d90c4a4 | ||
|
|
e60be2289e | ||
|
|
5ef94b29c3 | ||
|
|
33281c1e2e | ||
|
|
518a2cdab4 | ||
|
|
8235854e8a | ||
|
|
4cf3545a31 | ||
|
|
a2e37eb3d8 | ||
|
|
6352090e6d | ||
|
|
c407b92e80 | ||
|
|
250c48a289 | ||
|
|
e49ad98a9b | ||
|
|
263579b217 | ||
|
|
4665906ddd | ||
|
|
826a84478d | ||
|
|
b4c775663a | ||
|
|
58cde83fb0 | ||
|
|
1a9a984d26 | ||
|
|
05405024c0 | ||
|
|
d65f9a3064 | ||
|
|
d39f8237e0 | ||
|
|
0473abf51d | ||
|
|
c02d24f838 | ||
|
|
9e6187a736 | ||
|
|
4846743fdc |
@@ -969,6 +969,7 @@ find_path(ZMQ_INCLUDE_PATH zmq.h)
|
||||
find_library(ZMQ_LIB zmq)
|
||||
find_library(PGM_LIBRARY pgm)
|
||||
find_library(NORM_LIBRARY norm)
|
||||
find_library(GSSAPI_LIBRARY gssapi_krb5)
|
||||
find_library(PROTOLIB_LIBRARY protolib)
|
||||
find_library(SODIUM_LIBRARY sodium)
|
||||
|
||||
@@ -984,6 +985,9 @@ endif()
|
||||
if(NORM_LIBRARY)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${NORM_LIBRARY}")
|
||||
endif()
|
||||
if(GSSAPI_LIBRARY)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${GSSAPI_LIBRARY}")
|
||||
endif()
|
||||
if(PROTOLIB_LIBRARY)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${PROTOLIB_LIBRARY}")
|
||||
endif()
|
||||
|
||||
10
README.md
10
README.md
@@ -134,8 +134,8 @@ Dates are provided in the format YYYY-MM-DD.
|
||||
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
|
||||
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
|
||||
| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
|
||||
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.0.0 | New CLSAG transaction format
|
||||
| 2210720 | 2020-10-18 | v14 | v0.17.0.0 | v0.17.0.0 | forbid old MLSAG transaction format
|
||||
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.5 | New CLSAG transaction format
|
||||
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.5 | forbid old MLSAG transaction format
|
||||
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
|
||||
|
||||
X's indicate that these details have not been determined as of commit date.
|
||||
@@ -295,7 +295,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/monero-project/monero.git
|
||||
cd monero
|
||||
git checkout tags/v0.17.0.0
|
||||
git checkout tags/v0.17.1.5
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -412,10 +412,10 @@ application.
|
||||
cd monero
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.0.0'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.1.5'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.17.0.0
|
||||
git checkout v0.17.1.5
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -91,7 +91,7 @@ endif()
|
||||
|
||||
# Protobuf compilation test
|
||||
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
|
||||
execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_SOURCE_DIR}/cmake" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_SOURCE_DIR}/cmake/test-protobuf.proto" --cpp_out ${CMAKE_BINARY_DIR} RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
|
||||
execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_CURRENT_LIST_DIR}" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_CURRENT_LIST_DIR}/test-protobuf.proto" --cpp_out ${CMAKE_BINARY_DIR} RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
|
||||
if(RET)
|
||||
message(STATUS "Protobuf test generation failed: ${OUT} ${ERR}")
|
||||
endif()
|
||||
@@ -100,7 +100,7 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
SOURCES
|
||||
"${CMAKE_BINARY_DIR}/test-protobuf.pb.cc"
|
||||
"${CMAKE_SOURCE_DIR}/cmake/test-protobuf.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/test-protobuf.cpp"
|
||||
CMAKE_FLAGS
|
||||
"-DINCLUDE_DIRECTORIES=${Protobuf_INCLUDE_DIR};${CMAKE_BINARY_DIR}"
|
||||
"-DCMAKE_CXX_STANDARD=11"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
function (write_version tag)
|
||||
set(VERSIONTAG "${tag}" CACHE STRING "The tag portion of the Monero software version" FORCE)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/src/version.cpp.in" "${CMAKE_BINARY_DIR}/version.cpp")
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/../src/version.cpp.in" "${CMAKE_BINARY_DIR}/version.cpp")
|
||||
endfunction ()
|
||||
|
||||
find_package(Git QUIET)
|
||||
|
||||
@@ -51,6 +51,7 @@ rdln::readline_buffer::readline_buffer()
|
||||
|
||||
void rdln::readline_buffer::start()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
if(m_cout_buf != NULL)
|
||||
return;
|
||||
m_cout_buf = std::cout.rdbuf();
|
||||
@@ -60,6 +61,7 @@ void rdln::readline_buffer::start()
|
||||
|
||||
void rdln::readline_buffer::stop()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
if(m_cout_buf == NULL)
|
||||
return;
|
||||
std::cout.rdbuf(m_cout_buf);
|
||||
@@ -88,9 +90,9 @@ rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const
|
||||
|
||||
void rdln::readline_buffer::set_prompt(const std::string& prompt)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
if(m_cout_buf == NULL)
|
||||
return;
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
rl_set_prompt(std::string(m_prompt_length, ' ').c_str());
|
||||
rl_redisplay();
|
||||
rl_set_prompt(prompt.c_str());
|
||||
@@ -113,6 +115,12 @@ const std::vector<std::string>& rdln::readline_buffer::get_completions()
|
||||
int rdln::readline_buffer::sync()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
|
||||
if (m_cout_buf == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if RL_READLINE_VERSION < 0x0700
|
||||
char lbuf[2] = {0,0};
|
||||
char *line = NULL;
|
||||
|
||||
@@ -126,7 +126,7 @@ Setup for LXC:
|
||||
|
||||
```bash
|
||||
GH_USER=fluffypony
|
||||
VERSION=v0.17.0.0
|
||||
VERSION=v0.17.1.5
|
||||
|
||||
./gitian-build.py --setup $GH_USER $VERSION
|
||||
```
|
||||
@@ -182,7 +182,7 @@ If you chose to do detached signing using `--detach-sign` above (recommended), y
|
||||
|
||||
```bash
|
||||
GH_USER=fluffypony
|
||||
VERSION=v0.17.0.0
|
||||
VERSION=v0.17.1.5
|
||||
|
||||
gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert
|
||||
gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert
|
||||
|
||||
@@ -119,7 +119,7 @@ script: |
|
||||
for i in ${HOSTS}; do
|
||||
export PATH=${WRAP_DIR}:${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DCMAKE_BUILD_TYPE=Release
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_SKIP_RPATH=ON
|
||||
make ${MAKEOPTS}
|
||||
chmod 755 bin/*
|
||||
cp ../LICENSE bin
|
||||
|
||||
@@ -111,6 +111,11 @@ script: |
|
||||
rm -f $WRAP_DIR/extra_includes/i686-linux-gnu/asm
|
||||
ln -s /usr/include/x86_64-linux-gnu/asm $EXTRA_INCLUDES_BASE/i686-linux-gnu/asm
|
||||
|
||||
# glibc 2.23 breaks compatibility with <=2.19 use of lgamma function.
|
||||
# Hack the math header to restore the old behavior.
|
||||
mkdir $EXTRA_INCLUDES_BASE/bits
|
||||
sed -e '/__REDIRFROM .lgamma,/,+3s/_USE_/_DONTUSE_/g' /usr/include/x86_64-linux-gnu/bits/math-finite.h > $EXTRA_INCLUDES_BASE/bits/math-finite.h
|
||||
|
||||
# gcc 7+ honors SOURCE_DATE_EPOCH, no faketime needed
|
||||
export SOURCE_DATE_EPOCH=`date -d 2000-01-01T12:00:00 +%s`
|
||||
|
||||
@@ -127,14 +132,14 @@ script: |
|
||||
# Build dependencies for each host
|
||||
export TAR_OPTIONS=--mtime=2000-01-01T12:00:00
|
||||
for i in $HOSTS; do
|
||||
EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i"
|
||||
if [ -d "$EXTRA_INCLUDES" ]; then
|
||||
export C_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
ARCH_INCLUDES="$EXTRA_INCLUDES_BASE/$i"
|
||||
if [ -d "$ARCH_INCLUDES" ]; then
|
||||
EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}:${ARCH_INCLUDES}"
|
||||
else
|
||||
unset C_INCLUDE_PATH
|
||||
unset CPLUS_INCLUDE_PATH
|
||||
EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}"
|
||||
fi
|
||||
export C_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" V=1
|
||||
done
|
||||
|
||||
@@ -151,15 +156,15 @@ script: |
|
||||
for i in ${HOSTS}; do
|
||||
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
|
||||
mkdir build && cd build
|
||||
EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i"
|
||||
if [ -d "$EXTRA_INCLUDES" ]; then
|
||||
export C_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
ARCH_INCLUDES="$EXTRA_INCLUDES_BASE/$i"
|
||||
if [ -d "$ARCH_INCLUDES" ]; then
|
||||
EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}:${ARCH_INCLUDES}"
|
||||
else
|
||||
unset C_INCLUDE_PATH
|
||||
unset CPLUS_INCLUDE_PATH
|
||||
EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}"
|
||||
fi
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON
|
||||
export C_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES"
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON -DCMAKE_SKIP_RPATH=ON
|
||||
make ${MAKEOPTS}
|
||||
chmod 755 bin/*
|
||||
cp ../LICENSE bin
|
||||
|
||||
@@ -47,6 +47,7 @@ int main(int argc, char* argv[])
|
||||
epee::string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
uint32_t log_level = 0;
|
||||
uint64_t block_start = 0;
|
||||
uint64_t block_stop = 0;
|
||||
bool blocks_dat = false;
|
||||
|
||||
@@ -58,6 +59,7 @@ int main(int argc, char* argv[])
|
||||
po::options_description desc_cmd_sett("Command line options and settings options");
|
||||
const command_line::arg_descriptor<std::string> arg_output_file = {"output-file", "Specify output file", "", true};
|
||||
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
|
||||
const command_line::arg_descriptor<uint64_t> arg_block_start = {"block-start", "Start at block number", block_start};
|
||||
const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
|
||||
const command_line::arg_descriptor<bool> arg_blocks_dat = {"blocksdat", "Output in blocks.dat format", blocks_dat};
|
||||
|
||||
@@ -67,6 +69,7 @@ int main(int argc, char* argv[])
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_stagenet_on);
|
||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||
command_line::add_arg(desc_cmd_sett, arg_block_start);
|
||||
command_line::add_arg(desc_cmd_sett, arg_block_stop);
|
||||
command_line::add_arg(desc_cmd_sett, arg_blocks_dat);
|
||||
|
||||
@@ -97,6 +100,7 @@ int main(int argc, char* argv[])
|
||||
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
|
||||
else
|
||||
mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
|
||||
block_start = command_line::get_arg(vm, arg_block_start);
|
||||
block_stop = command_line::get_arg(vm, arg_block_stop);
|
||||
|
||||
LOG_PRINT_L0("Starting...");
|
||||
@@ -178,7 +182,7 @@ int main(int argc, char* argv[])
|
||||
else
|
||||
{
|
||||
BootstrapFile bootstrap;
|
||||
r = bootstrap.store_blockchain_raw(core_storage, NULL, output_file_path, block_stop);
|
||||
r = bootstrap.store_blockchain_raw(core_storage, NULL, output_file_path, block_start, block_stop);
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(r, 1, "Failed to export blockchain raw data");
|
||||
LOG_PRINT_L0("Blockchain raw data exported OK");
|
||||
|
||||
@@ -227,6 +227,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t block_first, block_last;
|
||||
uint64_t start_height = 1, seek_height;
|
||||
if (opt_resume)
|
||||
start_height = core.get_blockchain_storage().get_current_blockchain_height();
|
||||
@@ -235,10 +236,10 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
BootstrapFile bootstrap;
|
||||
std::streampos pos;
|
||||
// BootstrapFile bootstrap(import_file_path);
|
||||
uint64_t total_source_blocks = bootstrap.count_blocks(import_file_path, pos, seek_height);
|
||||
MINFO("bootstrap file last block number: " << total_source_blocks-1 << " (zero-based height) total blocks: " << total_source_blocks);
|
||||
uint64_t total_source_blocks = bootstrap.count_blocks(import_file_path, pos, seek_height, block_first);
|
||||
MINFO("bootstrap file last block number: " << total_source_blocks+block_first-1 << " (zero-based height) total blocks: " << total_source_blocks);
|
||||
|
||||
if (total_source_blocks-1 <= start_height)
|
||||
if (total_source_blocks+block_first-1 <= start_height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -260,7 +261,8 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
|
||||
// 4 byte magic + (currently) 1024 byte header structures
|
||||
uint8_t major_version, minor_version;
|
||||
bootstrap.seek_to_first_chunk(import_file, major_version, minor_version);
|
||||
uint64_t dummy;
|
||||
bootstrap.seek_to_first_chunk(import_file, major_version, minor_version, dummy, dummy);
|
||||
|
||||
std::string str1;
|
||||
char buffer1[1024];
|
||||
@@ -275,7 +277,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
|
||||
if (! block_stop)
|
||||
{
|
||||
block_stop = total_source_blocks - 1;
|
||||
block_stop = total_source_blocks+block_first - 1;
|
||||
}
|
||||
|
||||
// These are what we'll try to use, and they don't have to be a determination
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace
|
||||
|
||||
|
||||
|
||||
bool BootstrapFile::open_writer(const boost::filesystem::path& file_path)
|
||||
bool BootstrapFile::open_writer(const boost::filesystem::path& file_path, uint64_t start_block, uint64_t stop_block)
|
||||
{
|
||||
const boost::filesystem::path dir_path = file_path.parent_path();
|
||||
if (!dir_path.empty())
|
||||
@@ -78,7 +78,7 @@ bool BootstrapFile::open_writer(const boost::filesystem::path& file_path)
|
||||
m_raw_data_file = new std::ofstream();
|
||||
|
||||
bool do_initialize_file = false;
|
||||
uint64_t num_blocks = 0;
|
||||
uint64_t num_blocks = 0, block_first = 0;
|
||||
|
||||
if (! boost::filesystem::exists(file_path))
|
||||
{
|
||||
@@ -88,10 +88,12 @@ bool BootstrapFile::open_writer(const boost::filesystem::path& file_path)
|
||||
}
|
||||
else
|
||||
{
|
||||
num_blocks = count_blocks(file_path.string());
|
||||
MDEBUG("appending to existing file with height: " << num_blocks-1 << " total blocks: " << num_blocks);
|
||||
std::streampos dummy_pos;
|
||||
uint64_t dummy_height = 0;
|
||||
num_blocks = count_blocks(file_path.string(), dummy_pos, dummy_height, block_first);
|
||||
MDEBUG("appending to existing file with height: " << num_blocks+block_first-1 << " total blocks: " << num_blocks);
|
||||
}
|
||||
m_height = num_blocks;
|
||||
m_height = num_blocks+block_first;
|
||||
|
||||
if (do_initialize_file)
|
||||
m_raw_data_file->open(file_path.string(), std::ios_base::binary | std::ios_base::out | std::ios::trunc);
|
||||
@@ -106,13 +108,12 @@ bool BootstrapFile::open_writer(const boost::filesystem::path& file_path)
|
||||
return false;
|
||||
|
||||
if (do_initialize_file)
|
||||
initialize_file();
|
||||
initialize_file(start_block, stop_block);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BootstrapFile::initialize_file()
|
||||
bool BootstrapFile::initialize_file(uint64_t first_block, uint64_t last_block)
|
||||
{
|
||||
const uint32_t file_magic = blockchain_raw_magic;
|
||||
|
||||
@@ -129,8 +130,8 @@ bool BootstrapFile::initialize_file()
|
||||
bfi.header_size = header_size;
|
||||
|
||||
bootstrap::blocks_info bbi;
|
||||
bbi.block_first = 0;
|
||||
bbi.block_last = 0;
|
||||
bbi.block_first = first_block;
|
||||
bbi.block_last = last_block;
|
||||
bbi.block_last_pos = 0;
|
||||
|
||||
buffer_type buffer2;
|
||||
@@ -261,7 +262,7 @@ bool BootstrapFile::close()
|
||||
}
|
||||
|
||||
|
||||
bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_memory_pool* _tx_pool, boost::filesystem::path& output_file, uint64_t requested_block_stop)
|
||||
bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_memory_pool* _tx_pool, boost::filesystem::path& output_file, uint64_t start_block, uint64_t requested_block_stop)
|
||||
{
|
||||
uint64_t num_blocks_written = 0;
|
||||
m_max_chunk = 0;
|
||||
@@ -269,17 +270,11 @@ bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_mem
|
||||
m_tx_pool = _tx_pool;
|
||||
uint64_t progress_interval = 100;
|
||||
MINFO("Storing blocks raw data...");
|
||||
if (!BootstrapFile::open_writer(output_file))
|
||||
{
|
||||
MFATAL("failed to open raw file for write");
|
||||
return false;
|
||||
}
|
||||
block b;
|
||||
|
||||
// block_start, block_stop use 0-based height. m_height uses 1-based height. So to resume export
|
||||
// from last exported block, block_start doesn't need to add 1 here, as it's already at the next
|
||||
// height.
|
||||
uint64_t block_start = m_height;
|
||||
uint64_t block_stop = 0;
|
||||
MINFO("source blockchain height: " << m_blockchain_storage->get_current_blockchain_height()-1);
|
||||
if ((requested_block_stop > 0) && (requested_block_stop < m_blockchain_storage->get_current_blockchain_height()))
|
||||
@@ -292,6 +287,13 @@ bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_mem
|
||||
block_stop = m_blockchain_storage->get_current_blockchain_height() - 1;
|
||||
MINFO("Using block height of source blockchain: " << block_stop);
|
||||
}
|
||||
if (!BootstrapFile::open_writer(output_file, start_block, block_stop))
|
||||
{
|
||||
MFATAL("failed to open raw file for write");
|
||||
return false;
|
||||
}
|
||||
uint64_t block_start = m_height ? m_height : start_block;
|
||||
MINFO("Starting block height: " << block_start);
|
||||
for (m_cur_height = block_start; m_cur_height <= block_stop; ++m_cur_height)
|
||||
{
|
||||
// this method's height refers to 0-based height (genesis block = height 0)
|
||||
@@ -323,7 +325,8 @@ bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_mem
|
||||
return BootstrapFile::close();
|
||||
}
|
||||
|
||||
uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file, uint8_t &major_version, uint8_t &minor_version)
|
||||
uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file, uint8_t &major_version, uint8_t &minor_version,
|
||||
uint64_t &block_first, uint64_t &block_last)
|
||||
{
|
||||
uint32_t file_magic;
|
||||
|
||||
@@ -368,11 +371,35 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file, uint8_t
|
||||
MINFO("bootstrap magic size: " << sizeof(file_magic));
|
||||
MINFO("bootstrap header size: " << bfi.header_size);
|
||||
|
||||
uint32_t buflen_blocks_info;
|
||||
|
||||
import_file.read(buf1, sizeof(buflen_blocks_info));
|
||||
str1.assign(buf1, sizeof(buflen_blocks_info));
|
||||
if (! import_file)
|
||||
throw std::runtime_error("Error reading expected number of bytes");
|
||||
if (! ::serialization::parse_binary(str1, buflen_blocks_info))
|
||||
throw std::runtime_error("Error in deserialization of buflen_blocks_info");
|
||||
MINFO("bootstrap::blocks_info size: " << buflen_blocks_info);
|
||||
|
||||
if (buflen_blocks_info > sizeof(buf1))
|
||||
throw std::runtime_error("Error: bootstrap::blocks_info size exceeds buffer size");
|
||||
import_file.read(buf1, buflen_blocks_info);
|
||||
if (! import_file)
|
||||
throw std::runtime_error("Error reading expected number of bytes");
|
||||
str1.assign(buf1, buflen_blocks_info);
|
||||
bootstrap::blocks_info bbi;
|
||||
if (! ::serialization::parse_binary(str1, bbi))
|
||||
throw std::runtime_error("Error in deserialization of bootstrap::blocks_info");
|
||||
MINFO("bootstrap first block:" << bbi.block_first);
|
||||
MINFO("bootstrap last block:" << bbi.block_last);
|
||||
|
||||
uint64_t full_header_size = sizeof(file_magic) + bfi.header_size;
|
||||
import_file.seekg(full_header_size);
|
||||
|
||||
major_version = bfi.major_version;
|
||||
minor_version = bfi.minor_version;
|
||||
block_first = bbi.block_first;
|
||||
block_last = bbi.block_last;
|
||||
return full_header_size;
|
||||
}
|
||||
|
||||
@@ -436,13 +463,14 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
|
||||
{
|
||||
std::streampos dummy_pos;
|
||||
uint64_t dummy_height = 0;
|
||||
return count_blocks(import_file_path, dummy_pos, dummy_height);
|
||||
return count_blocks(import_file_path, dummy_pos, dummy_height, dummy_height);
|
||||
}
|
||||
|
||||
// If seek_height is non-zero on entry, return a stream position <= this height when finished.
|
||||
// And return the actual height corresponding to this position. Allows the caller to locate its
|
||||
// starting position without having to reread the entire file again.
|
||||
uint64_t BootstrapFile::count_blocks(const std::string& import_file_path, std::streampos &start_pos, uint64_t& seek_height)
|
||||
uint64_t BootstrapFile::count_blocks(const std::string& import_file_path, std::streampos &start_pos,
|
||||
uint64_t& seek_height, uint64_t &block_first)
|
||||
{
|
||||
boost::filesystem::path raw_file_path(import_file_path);
|
||||
boost::system::error_code ec;
|
||||
@@ -464,7 +492,8 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path, std::s
|
||||
|
||||
uint64_t full_header_size; // 4 byte magic + length of header structures
|
||||
uint8_t major_version, minor_version;
|
||||
full_header_size = seek_to_first_chunk(import_file, major_version, minor_version);
|
||||
uint64_t block_last;
|
||||
full_header_size = seek_to_first_chunk(import_file, major_version, minor_version, block_first, block_last);
|
||||
|
||||
MINFO("Scanning blockchain from bootstrap file...");
|
||||
bool quit = false;
|
||||
@@ -473,11 +502,11 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path, std::s
|
||||
|
||||
while (! quit)
|
||||
{
|
||||
if (start_height && h + progress_interval >= start_height - 1)
|
||||
if (start_height && h + block_first + progress_interval >= start_height - 1)
|
||||
{
|
||||
start_height = 0;
|
||||
start_pos = import_file.tellg();
|
||||
seek_height = h;
|
||||
seek_height = h + block_first;
|
||||
}
|
||||
bytes_read += count_bytes(import_file, progress_interval, blocks, quit);
|
||||
h += blocks;
|
||||
|
||||
@@ -57,12 +57,12 @@ class BootstrapFile
|
||||
public:
|
||||
|
||||
uint64_t count_bytes(std::ifstream& import_file, uint64_t blocks, uint64_t& h, bool& quit);
|
||||
uint64_t count_blocks(const std::string& dir_path, std::streampos& start_pos, uint64_t& seek_height);
|
||||
uint64_t count_blocks(const std::string& dir_path, std::streampos& start_pos, uint64_t& seek_height, uint64_t& block_first);
|
||||
uint64_t count_blocks(const std::string& dir_path);
|
||||
uint64_t seek_to_first_chunk(std::ifstream& import_file, uint8_t &major_version, uint8_t &minor_version);
|
||||
uint64_t seek_to_first_chunk(std::ifstream& import_file, uint8_t &major_version, uint8_t &minor_version, uint64_t &block_first, uint64_t &block_last);
|
||||
|
||||
bool store_blockchain_raw(cryptonote::Blockchain* cs, cryptonote::tx_memory_pool* txp,
|
||||
boost::filesystem::path& output_file, uint64_t use_block_height=0);
|
||||
boost::filesystem::path& output_file, uint64_t start_block=0, uint64_t stop_block=0);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -75,8 +75,8 @@ protected:
|
||||
boost::iostreams::stream<boost::iostreams::back_insert_device<buffer_type>>* m_output_stream;
|
||||
|
||||
// open export file for write
|
||||
bool open_writer(const boost::filesystem::path& file_path);
|
||||
bool initialize_file();
|
||||
bool open_writer(const boost::filesystem::path& file_path, uint64_t start_block, uint64_t stop_block);
|
||||
bool initialize_file(uint64_t start_block, uint64_t stop_block);
|
||||
bool close();
|
||||
void write_block(block& block);
|
||||
void flush_chunk();
|
||||
|
||||
Binary file not shown.
@@ -237,6 +237,11 @@ namespace cryptonote
|
||||
ADD_CHECKPOINT2(2046000, "5e867f0b8baefed9244a681df97fc885d8ab36c3dfcd24c7a3abf3b8ac8b8314", "0x9cb8b6ff2978c6");
|
||||
ADD_CHECKPOINT2(2092500, "c4e00820c9c7989b49153d5e90ae095a18a11d990e82fcc3be54e6ed785472b5", "0xb4e585a31369cb");
|
||||
ADD_CHECKPOINT2(2182500, "0d22b5f81982eff21d094af9e821dc2007e6342069e3b1a37b15d97646353124", "0xead4a874083492");
|
||||
ADD_CHECKPOINT2(2193000, "6e91b917a40309f89f75f2c8d7be5a6d1a3c425634f07f7d1867bd32d2e602ed", "0xf085140f17389d");
|
||||
ADD_CHECKPOINT2(2206500, "dd3c8590f33eaa546a4ce69d02f27fd58a2f115cd32d733bd9426f8278f0cb8a", "0xf8725275799f0d");
|
||||
ADD_CHECKPOINT2(2210500, "ed17259215ac6aabe6e8252b5b5eff613d2e69cc2111173e567109aa78301911", "0xfbcb50a9a6a433");
|
||||
ADD_CHECKPOINT2(2224000, "e34bc71301600df96d08aaa6b0bde932cba1b06a3dd57076e3f664a078810a80", "0x1052fc256fceb6f");
|
||||
ADD_CHECKPOINT2(2235500, "3eac1a1253495733e10d00fd5e8e1639741566d91bae38bc6d3342af6b75da53", "0x10cea232ce71d23");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,11 +102,11 @@
|
||||
|
||||
|
||||
#define CRYPTONOTE_DANDELIONPP_STEMS 2 // number of outgoing stem connections per epoch
|
||||
#define CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY 10 // out of 100
|
||||
#define CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY 20 // out of 100
|
||||
#define CRYPTONOTE_DANDELIONPP_MIN_EPOCH 10 // minutes
|
||||
#define CRYPTONOTE_DANDELIONPP_EPOCH_RANGE 30 // seconds
|
||||
#define CRYPTONOTE_DANDELIONPP_FLUSH_AVERAGE 5 // seconds average for poisson distributed fluff flush
|
||||
#define CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE 173 // seconds (see tx_pool.cpp for more info)
|
||||
#define CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE 39 // seconds (see tx_pool.cpp for more info)
|
||||
|
||||
// see src/cryptonote_protocol/levin_notify.cpp
|
||||
#define CRYPTONOTE_NOISE_MIN_EPOCH 5 // minutes
|
||||
@@ -128,7 +128,7 @@
|
||||
#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000
|
||||
#define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000
|
||||
|
||||
#define P2P_DEFAULT_CONNECTIONS_COUNT 8
|
||||
#define P2P_DEFAULT_CONNECTIONS_COUNT 12
|
||||
#define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes
|
||||
#define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size
|
||||
#define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250
|
||||
|
||||
@@ -3068,9 +3068,21 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
if (tx.version >= 2) {
|
||||
if (tx.rct_signatures.type <= rct::RCTTypeBulletproof2)
|
||||
{
|
||||
MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << (HF_VERSION_CLSAG + 1));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
// two MLSAG txes went in due to a bug with txes that went into the txpool before the fork, grandfather them in
|
||||
static const char * grandfathered[2] = { "c5151944f0583097ba0c88cd0f43e7fabb3881278aa2f73b3b0a007c5d34e910", "6f2f117cde6fbcf8d4a6ef8974fcac744726574ac38cf25d3322c996b21edd4c" };
|
||||
crypto::hash h0, h1;
|
||||
epee::string_tools::hex_to_pod(grandfathered[0], h0);
|
||||
epee::string_tools::hex_to_pod(grandfathered[1], h1);
|
||||
if (cryptonote::get_transaction_hash(tx) == h0 || cryptonote::get_transaction_hash(tx) == h1)
|
||||
{
|
||||
MDEBUG("Grandfathering cryptonote::get_transaction_hash(tx) in");
|
||||
}
|
||||
else
|
||||
{
|
||||
MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << (HF_VERSION_CLSAG + 1));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5364,7 +5376,7 @@ void Blockchain::cancel()
|
||||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
static const char expected_block_hashes_hash[] = "8da80ca560793f252d1d4ed449c85d75c74867f3f86b8832c8e3f88b1cbb6ae3";
|
||||
static const char expected_block_hashes_hash[] = "3a2a0720f7ed3573d2b632f7ba127e2f97edac3af34bf924df57c13a88bf2460";
|
||||
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
|
||||
{
|
||||
if (get_checkpoints == nullptr || !m_fast_sync)
|
||||
|
||||
@@ -1510,6 +1510,11 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::is_synchronized() const
|
||||
{
|
||||
return m_pprotocol != nullptr && m_pprotocol->is_synchronized();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::on_synchronized()
|
||||
{
|
||||
m_miner.on_synchronized();
|
||||
@@ -1725,7 +1730,7 @@ namespace cryptonote
|
||||
m_starter_message_showed = true;
|
||||
}
|
||||
|
||||
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
|
||||
relay_txpool_transactions(); // txpool handles periodic DB checking
|
||||
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_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this));
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace cryptonote
|
||||
*
|
||||
* @note see Blockchain::get_current_blockchain_height()
|
||||
*/
|
||||
uint64_t get_current_blockchain_height() const;
|
||||
virtual uint64_t get_current_blockchain_height() const final;
|
||||
|
||||
/**
|
||||
* @brief get the hash and height of the most recent block
|
||||
@@ -637,6 +637,13 @@ namespace cryptonote
|
||||
*/
|
||||
std::string print_pool(bool short_format) const;
|
||||
|
||||
/**
|
||||
* @brief gets the core synchronization status
|
||||
*
|
||||
* @return core synchronization status
|
||||
*/
|
||||
virtual bool is_synchronized() const final;
|
||||
|
||||
/**
|
||||
* @copydoc miner::on_synchronized
|
||||
*
|
||||
@@ -1065,7 +1072,6 @@ namespace cryptonote
|
||||
|
||||
epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled
|
||||
epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; //!< interval for checking HardFork status
|
||||
epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions
|
||||
epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions
|
||||
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
|
||||
epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace cryptonote
|
||||
virtual ~i_core_events() noexcept
|
||||
{}
|
||||
|
||||
virtual uint64_t get_current_blockchain_height() const = 0;
|
||||
virtual bool is_synchronized() const = 0;
|
||||
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,11 +75,11 @@ namespace cryptonote
|
||||
not ideal since a blackhole is more likely to reveal earlier nodes in
|
||||
the chain.
|
||||
|
||||
This value was calculated with k=10, ep=0.10, and hop = 175 ms. A
|
||||
This value was calculated with k=5, ep=0.10, and hop = 175 ms. A
|
||||
testrun from a recent Intel laptop took ~80ms to
|
||||
receive+parse+proces+send transaction. At least 50ms will be added to
|
||||
the latency if crossing an ocean. So 175ms is the fudge factor for
|
||||
a single hop with 173s being the embargo timer. */
|
||||
a single hop with 39s being the embargo timer. */
|
||||
constexpr const std::chrono::seconds dandelionpp_embargo_average{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE};
|
||||
|
||||
//TODO: constants such as these should at least be in the header,
|
||||
@@ -91,6 +91,9 @@ namespace cryptonote
|
||||
time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
|
||||
float const ACCEPT_THRESHOLD = 1.0f;
|
||||
|
||||
//! Max DB check interval for relayable txes
|
||||
constexpr const std::chrono::minutes max_relayable_check{2};
|
||||
|
||||
constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE};
|
||||
|
||||
// a kind of increasing backoff within min/max bounds
|
||||
@@ -115,12 +118,21 @@ namespace cryptonote
|
||||
else
|
||||
return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
}
|
||||
|
||||
// external lock must be held for the comparison+set to work properly
|
||||
void set_if_less(std::atomic<time_t>& next_check, const time_t candidate) noexcept
|
||||
{
|
||||
if (candidate < next_check.load(std::memory_order_relaxed))
|
||||
next_check = candidate;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------
|
||||
tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false)
|
||||
tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false), m_next_check(std::time(nullptr))
|
||||
{
|
||||
|
||||
// class code expects unsigned values throughout
|
||||
if (m_next_check < time_t(0))
|
||||
throw std::runtime_error{"Unexpected time_t (system clock) value"};
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version)
|
||||
@@ -314,7 +326,10 @@ namespace cryptonote
|
||||
using clock = std::chrono::system_clock;
|
||||
auto last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max();
|
||||
if (tx_relay == relay_method::forward)
|
||||
{
|
||||
last_relayed_time = clock::to_time_t(clock::now() + crypto::random_poisson_seconds{forward_delay_average}());
|
||||
set_if_less(m_next_check, time_t(last_relayed_time));
|
||||
}
|
||||
// else the `set_relayed` function will adjust the time accordingly later
|
||||
|
||||
//update transactions container
|
||||
@@ -728,16 +743,22 @@ namespace cryptonote
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
//TODO: investigate whether boolean return is appropriate
|
||||
bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) const
|
||||
bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs)
|
||||
{
|
||||
std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps;
|
||||
using clock = std::chrono::system_clock;
|
||||
|
||||
const uint64_t now = time(NULL);
|
||||
if (uint64_t{std::numeric_limits<time_t>::max()} < now || time_t(now) < m_next_check)
|
||||
return false;
|
||||
|
||||
uint64_t next_check = clock::to_time_t(clock::from_time_t(time_t(now)) + max_relayable_check);
|
||||
std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps;
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
LockedTXN lock(m_blockchain.get_db());
|
||||
txs.reserve(m_blockchain.get_txpool_tx_count());
|
||||
m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){
|
||||
m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps, &next_check](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){
|
||||
// 0 fee transactions are never relayed
|
||||
if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay)
|
||||
{
|
||||
@@ -747,7 +768,10 @@ namespace cryptonote
|
||||
case relay_method::stem:
|
||||
case relay_method::forward:
|
||||
if (meta.last_relayed_time > now)
|
||||
{
|
||||
next_check = std::min(next_check, meta.last_relayed_time);
|
||||
return true; // continue to next tx
|
||||
}
|
||||
change_timestamps.emplace_back(txid, meta);
|
||||
break;
|
||||
default:
|
||||
@@ -792,6 +816,8 @@ namespace cryptonote
|
||||
elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time);
|
||||
m_blockchain.update_txpool_tx(elem.first, elem.second);
|
||||
}
|
||||
|
||||
m_next_check = time_t(next_check);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
@@ -799,6 +825,7 @@ namespace cryptonote
|
||||
{
|
||||
crypto::random_poisson_seconds embargo_duration{dandelionpp_embargo_average};
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
uint64_t next_relay = uint64_t{std::numeric_limits<time_t>::max()};
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
@@ -815,7 +842,10 @@ namespace cryptonote
|
||||
meta.relayed = true;
|
||||
|
||||
if (meta.dandelionpp_stem)
|
||||
{
|
||||
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now + embargo_duration());
|
||||
next_relay = std::min(next_relay, meta.last_relayed_time);
|
||||
}
|
||||
else
|
||||
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now);
|
||||
|
||||
@@ -829,6 +859,7 @@ namespace cryptonote
|
||||
}
|
||||
}
|
||||
lock.commit();
|
||||
set_if_less(m_next_check, time_t(next_relay));
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
size_t tx_memory_pool::get_transactions_count(bool include_sensitive) const
|
||||
@@ -1391,7 +1422,10 @@ namespace cryptonote
|
||||
txpool_tx_meta_t meta;
|
||||
if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
|
||||
{
|
||||
MERROR(" failed to find tx meta");
|
||||
static bool warned = false;
|
||||
if (!warned)
|
||||
MERROR(" failed to find tx meta: " << sorted_it->second << " (will only print once)");
|
||||
warned = true;
|
||||
continue;
|
||||
}
|
||||
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#pragma once
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
@@ -329,11 +330,14 @@ namespace cryptonote
|
||||
* isn't old enough that relaying it is considered harmful
|
||||
* Note a transaction can be "relayable" even if do_not_relay is true
|
||||
*
|
||||
* This function will skip all DB checks if an insufficient amount of
|
||||
* time since the last call.
|
||||
*
|
||||
* @param txs return-by-reference the transactions and their hashes
|
||||
*
|
||||
* @return true
|
||||
* @return True if DB was checked, false if DB checks skipped.
|
||||
*/
|
||||
bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs) const;
|
||||
bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs);
|
||||
|
||||
/**
|
||||
* @brief tell the pool that certain transactions were just relayed
|
||||
@@ -609,6 +613,9 @@ private:
|
||||
mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache;
|
||||
|
||||
std::unordered_map<crypto::hash, transaction> m_parsed_tx_cache;
|
||||
|
||||
//! Next timestamp that a DB check for relayable txes is allowed
|
||||
std::atomic<time_t> m_next_check;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace cryptonote
|
||||
bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
|
||||
bool on_callback(cryptonote_connection_context& context);
|
||||
t_core& get_core(){return m_core;}
|
||||
bool is_synchronized(){return m_synchronized;}
|
||||
virtual bool is_synchronized() const final { return !no_sync() && m_synchronized; }
|
||||
void log_connections();
|
||||
std::list<connection_info> get_connections();
|
||||
const block_queue &get_block_queue() const { return m_block_queue; }
|
||||
|
||||
@@ -430,7 +430,7 @@ namespace cryptonote
|
||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||
return 1;
|
||||
if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Received new block while syncing, ignored");
|
||||
return 1;
|
||||
@@ -501,7 +501,7 @@ namespace cryptonote
|
||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||
return 1;
|
||||
if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Received new block while syncing, ignored");
|
||||
return 1;
|
||||
@@ -929,7 +929,7 @@ namespace cryptonote
|
||||
// while syncing, core will lock for a long time, so we ignore
|
||||
// those txes as they aren't really needed anyway, and avoid a
|
||||
// long block before replying
|
||||
if(!is_synchronized() || m_no_sync)
|
||||
if(!is_synchronized())
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Received new tx while syncing, ignored");
|
||||
return 1;
|
||||
@@ -1091,6 +1091,13 @@ namespace cryptonote
|
||||
|
||||
//epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
|
||||
|
||||
if(arg.blocks.empty())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: no blocks");
|
||||
drop_connection(context, true, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
if(context.m_last_response_height > arg.current_blockchain_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
|
||||
@@ -2538,7 +2545,7 @@ skip:
|
||||
local mempool before doing the relay. The code was already updating the
|
||||
DB twice on received transactions - it is difficult to workaround this
|
||||
due to the internal design. */
|
||||
return m_p2p->send_txs(std::move(arg.txs), zone, source, m_core, tx_relay) != epee::net_utils::zone::invalid;
|
||||
return m_p2p->send_txs(std::move(arg.txs), zone, source, tx_relay) != epee::net_utils::zone::invalid;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace cryptonote
|
||||
/************************************************************************/
|
||||
struct i_cryptonote_protocol
|
||||
{
|
||||
virtual bool is_synchronized() const = 0;
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone, relay_method tx_relay)=0;
|
||||
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
|
||||
@@ -50,6 +51,10 @@ namespace cryptonote
|
||||
/************************************************************************/
|
||||
struct cryptonote_protocol_stub: public i_cryptonote_protocol
|
||||
{
|
||||
virtual bool is_synchronized() const final
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -105,8 +105,44 @@ namespace levin
|
||||
return std::chrono::steady_clock::duration{crypto::rand_range(rep(0), range.count())};
|
||||
}
|
||||
|
||||
//! \return All outgoing connections supporting fragments in `connections`.
|
||||
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p)
|
||||
uint64_t get_median_remote_height(connections& p2p)
|
||||
{
|
||||
std::vector<uint64_t> remote_heights;
|
||||
remote_heights.reserve(connection_id_reserve_size);
|
||||
p2p.foreach_connection([&remote_heights] (detail::p2p_context& context) {
|
||||
if (!context.m_is_income)
|
||||
{
|
||||
remote_heights.emplace_back(context.m_remote_blockchain_height);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (remote_heights.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size_t n = remote_heights.size() / 2;
|
||||
std::sort(remote_heights.begin(), remote_heights.end());
|
||||
if (remote_heights.size() % 2 != 0)
|
||||
{
|
||||
return remote_heights[n];
|
||||
}
|
||||
return remote_heights[n-1];
|
||||
}
|
||||
|
||||
uint64_t get_blockchain_height(connections& p2p, const i_core_events* core)
|
||||
{
|
||||
const uint64_t local_blockchain_height = core->get_current_blockchain_height();
|
||||
if (core->is_synchronized())
|
||||
{
|
||||
return local_blockchain_height;
|
||||
}
|
||||
return std::max(local_blockchain_height, get_median_remote_height(p2p));
|
||||
}
|
||||
|
||||
//! \return Outgoing connections supporting fragments in `connections` filtered by blockchain height.
|
||||
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, uint64_t blockchain_height)
|
||||
{
|
||||
std::vector<boost::uuids::uuid> outs;
|
||||
outs.reserve(connection_id_reserve_size);
|
||||
@@ -115,15 +151,21 @@ namespace levin
|
||||
the reserve call so a strand is not used. Investigate if there is lots
|
||||
of waiting in here. */
|
||||
|
||||
p2p.foreach_connection([&outs] (detail::p2p_context& context) {
|
||||
if (!context.m_is_income)
|
||||
p2p.foreach_connection([&outs, blockchain_height] (detail::p2p_context& context) {
|
||||
if (!context.m_is_income && context.m_remote_blockchain_height >= blockchain_height)
|
||||
outs.emplace_back(context.m_connection_id);
|
||||
return true;
|
||||
});
|
||||
|
||||
MDEBUG("Found " << outs.size() << " out connections having height >= " << blockchain_height);
|
||||
return outs;
|
||||
}
|
||||
|
||||
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, const i_core_events* core)
|
||||
{
|
||||
return get_out_connections(p2p, get_blockchain_height(p2p, core));
|
||||
}
|
||||
|
||||
std::string make_tx_payload(std::vector<blobdata>&& txs, const bool pad, const bool fluff)
|
||||
{
|
||||
NOTIFY_NEW_TRANSACTIONS::request request{};
|
||||
@@ -233,7 +275,7 @@ namespace levin
|
||||
{
|
||||
struct zone
|
||||
{
|
||||
explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, bool is_public, bool pad_txs)
|
||||
explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
|
||||
: p2p(std::move(p2p)),
|
||||
noise(std::move(noise_in)),
|
||||
next_epoch(io_service),
|
||||
@@ -241,9 +283,9 @@ namespace levin
|
||||
strand(io_service),
|
||||
map(),
|
||||
channels(),
|
||||
flush_time(std::chrono::steady_clock::time_point::max()),
|
||||
connection_count(0),
|
||||
is_public(is_public),
|
||||
flush_callbacks(0),
|
||||
nzone(zone),
|
||||
pad_txs(pad_txs),
|
||||
fluffing(false)
|
||||
{
|
||||
@@ -258,9 +300,9 @@ namespace levin
|
||||
boost::asio::io_service::strand strand;
|
||||
net::dandelionpp::connection_map map;//!< Tracks outgoing uuid's for noise channels or Dandelion++ stems
|
||||
std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand`
|
||||
std::chrono::steady_clock::time_point flush_time; //!< Next expected Dandelion++ fluff flush
|
||||
std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time
|
||||
const bool is_public; //!< Zone is public ipv4/ipv6 connections
|
||||
std::uint32_t flush_callbacks; //!< Number of active fluff flush callbacks queued
|
||||
const epee::net_utils::zone nzone; //!< Zone is public ipv4/ipv6 connections, or i2p or tor
|
||||
const bool pad_txs; //!< Pad txs to the next boundary for privacy
|
||||
bool fluffing; //!< Zone is in Dandelion++ fluff epoch
|
||||
};
|
||||
@@ -297,7 +339,8 @@ namespace levin
|
||||
if (!channel.connection.is_nil())
|
||||
channel.queue.push_back(std::move(message_));
|
||||
else if (destination_ == 0 && zone_->connection_count == 0)
|
||||
MWARNING("Unable to send transaction(s) over anonymity network - no available outbound connections");
|
||||
MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
|
||||
" - no available outbound connections");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -305,7 +348,6 @@ namespace levin
|
||||
struct fluff_flush
|
||||
{
|
||||
std::shared_ptr<detail::zone> zone_;
|
||||
std::chrono::steady_clock::time_point flush_time_;
|
||||
|
||||
static void queue(std::shared_ptr<detail::zone> zone, const std::chrono::steady_clock::time_point flush_time)
|
||||
{
|
||||
@@ -313,28 +355,21 @@ namespace levin
|
||||
assert(zone->strand.running_in_this_thread());
|
||||
|
||||
detail::zone& this_zone = *zone;
|
||||
this_zone.flush_time = flush_time;
|
||||
++this_zone.flush_callbacks;
|
||||
this_zone.flush_txs.expires_at(flush_time);
|
||||
this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone), flush_time}));
|
||||
this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone)}));
|
||||
}
|
||||
|
||||
void operator()(const boost::system::error_code error)
|
||||
{
|
||||
if (!zone_ || !zone_->p2p)
|
||||
if (!zone_ || !zone_->flush_callbacks || --zone_->flush_callbacks || !zone_->p2p)
|
||||
return;
|
||||
|
||||
assert(zone_->strand.running_in_this_thread());
|
||||
|
||||
const bool timer_error = bool(error);
|
||||
if (timer_error)
|
||||
{
|
||||
if (error != boost::system::errc::operation_canceled)
|
||||
throw boost::system::system_error{error, "fluff_flush timer failed"};
|
||||
|
||||
// new timer canceled this one set in future
|
||||
if (zone_->flush_time < flush_time_)
|
||||
return;
|
||||
}
|
||||
if (timer_error && error != boost::system::errc::operation_canceled)
|
||||
throw boost::system::system_error{error, "fluff_flush timer failed"};
|
||||
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
auto next_flush = std::chrono::steady_clock::time_point::max();
|
||||
@@ -370,8 +405,6 @@ namespace levin
|
||||
|
||||
if (next_flush != std::chrono::steady_clock::time_point::max())
|
||||
fluff_flush::queue(std::move(zone_), next_flush);
|
||||
else
|
||||
zone_->flush_time = next_flush; // signal that no timer is set
|
||||
}
|
||||
};
|
||||
|
||||
@@ -406,13 +439,11 @@ namespace levin
|
||||
|
||||
MDEBUG("Queueing " << txs.size() << " transaction(s) for Dandelion++ fluffing");
|
||||
|
||||
bool available = false;
|
||||
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush, &available] (detail::p2p_context& context)
|
||||
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context)
|
||||
{
|
||||
// When i2p/tor, only fluff to outbound connections
|
||||
if (source != context.m_connection_id && (zone->is_public || !context.m_is_income))
|
||||
if (source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
|
||||
{
|
||||
available = true;
|
||||
if (context.fluff_txs.empty())
|
||||
context.flush_time = now + (context.m_is_income ? in_duration() : out_duration());
|
||||
|
||||
@@ -424,10 +455,9 @@ namespace levin
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!available)
|
||||
if (next_flush == std::chrono::steady_clock::time_point::max())
|
||||
MWARNING("Unable to send transaction(s), no available connections");
|
||||
|
||||
if (next_flush < zone->flush_time)
|
||||
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expires_at())
|
||||
fluff_flush::queue(std::move(zone), next_flush);
|
||||
}
|
||||
};
|
||||
@@ -524,12 +554,7 @@ namespace levin
|
||||
if (!zone_ || !core_ || txs_.empty())
|
||||
return;
|
||||
|
||||
if (zone_->fluffing)
|
||||
{
|
||||
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff);
|
||||
fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_);
|
||||
}
|
||||
else // forward tx in stem
|
||||
if (!zone_->fluffing)
|
||||
{
|
||||
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::stem);
|
||||
for (int tries = 2; 0 < tries; tries--)
|
||||
@@ -544,11 +569,14 @@ namespace levin
|
||||
}
|
||||
|
||||
// connection list may be outdated, try again
|
||||
update_channels::run(zone_, get_out_connections(*zone_->p2p));
|
||||
update_channels::run(zone_, get_out_connections(*zone_->p2p, core_));
|
||||
}
|
||||
|
||||
MERROR("Unable to send transaction(s) via Dandelion++ stem");
|
||||
}
|
||||
|
||||
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff);
|
||||
fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -577,7 +605,7 @@ namespace levin
|
||||
|
||||
assert(zone_->strand.running_in_this_thread());
|
||||
|
||||
if (zone_->is_public)
|
||||
if (zone_->nzone == epee::net_utils::zone::public_)
|
||||
MDEBUG("Starting new Dandelion++ epoch: " << (fluffing_ ? "fluff" : "stem"));
|
||||
|
||||
zone_->map = std::move(map_);
|
||||
@@ -591,8 +619,9 @@ namespace levin
|
||||
{
|
||||
std::shared_ptr<detail::zone> zone_;
|
||||
const std::size_t channel_;
|
||||
const i_core_events* core_;
|
||||
|
||||
static void wait(const std::chrono::steady_clock::time_point start, std::shared_ptr<detail::zone> zone, const std::size_t index)
|
||||
static void wait(const std::chrono::steady_clock::time_point start, std::shared_ptr<detail::zone> zone, const std::size_t index, const i_core_events* core)
|
||||
{
|
||||
if (!zone)
|
||||
return;
|
||||
@@ -600,7 +629,7 @@ namespace levin
|
||||
noise_channel& channel = zone->channels.at(index);
|
||||
channel.next_noise.expires_at(start + noise_min_delay + random_duration(noise_delay_range));
|
||||
channel.next_noise.async_wait(
|
||||
channel.strand.wrap(send_noise{std::move(zone), index})
|
||||
channel.strand.wrap(send_noise{std::move(zone), index, core})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -644,16 +673,18 @@ namespace levin
|
||||
{
|
||||
channel.active = nullptr;
|
||||
channel.connection = boost::uuids::nil_uuid();
|
||||
auto height = get_blockchain_height(*zone_->p2p, core_);
|
||||
|
||||
auto connections = get_out_connections(*zone_->p2p);
|
||||
auto connections = get_out_connections(*zone_->p2p, height);
|
||||
if (connections.empty())
|
||||
MWARNING("Lost all outbound connections to anonymity network - currently unable to send transaction(s)");
|
||||
MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
|
||||
" - no suitable outbound connections at height " << height);
|
||||
|
||||
zone_->strand.post(update_channels{zone_, std::move(connections)});
|
||||
}
|
||||
}
|
||||
|
||||
wait(start, std::move(zone_), channel_);
|
||||
wait(start, std::move(zone_), channel_, core_);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -665,6 +696,7 @@ namespace levin
|
||||
std::chrono::seconds min_epoch_;
|
||||
std::chrono::seconds epoch_range_;
|
||||
std::size_t count_;
|
||||
const i_core_events* core_;
|
||||
|
||||
//! \pre Should not be invoked within any strand to prevent blocking.
|
||||
void operator()(const boost::system::error_code error = {})
|
||||
@@ -677,8 +709,9 @@ namespace levin
|
||||
|
||||
const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY;
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
auto connections = get_out_connections(*(zone_->p2p), core_);
|
||||
zone_->strand.dispatch(
|
||||
change_channels{zone_, net::dandelionpp::connection_map{get_out_connections(*(zone_->p2p)), count_}, fluffing}
|
||||
change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing}
|
||||
);
|
||||
|
||||
detail::zone& alias = *zone_;
|
||||
@@ -688,24 +721,25 @@ namespace levin
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, const bool is_public, const bool pad_txs)
|
||||
: zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), is_public, pad_txs))
|
||||
notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core)
|
||||
: zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), zone, pad_txs))
|
||||
, core_(std::addressof(core))
|
||||
{
|
||||
if (!zone_->p2p)
|
||||
throw std::logic_error{"cryptonote::levin::notify cannot have nullptr p2p argument"};
|
||||
|
||||
const bool noise_enabled = !zone_->noise.empty();
|
||||
if (noise_enabled || is_public)
|
||||
if (noise_enabled || zone == epee::net_utils::zone::public_)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto min_epoch = noise_enabled ? noise_min_epoch : dandelionpp_min_epoch;
|
||||
const auto epoch_range = noise_enabled ? noise_epoch_range : dandelionpp_epoch_range;
|
||||
const std::size_t out_count = noise_enabled ? CRYPTONOTE_NOISE_CHANNELS : CRYPTONOTE_DANDELIONPP_STEMS;
|
||||
|
||||
start_epoch{zone_, min_epoch, epoch_range, out_count}();
|
||||
start_epoch{zone_, min_epoch, epoch_range, out_count, core_}();
|
||||
|
||||
for (std::size_t channel = 0; channel < zone_->channels.size(); ++channel)
|
||||
send_noise::wait(now, zone_, channel);
|
||||
send_noise::wait(now, zone_, channel, core_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,7 +760,7 @@ namespace levin
|
||||
return;
|
||||
|
||||
zone_->strand.dispatch(
|
||||
update_channels{zone_, get_out_connections(*(zone_->p2p))}
|
||||
update_channels{zone_, get_out_connections(*(zone_->p2p), core_)}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -753,7 +787,7 @@ namespace levin
|
||||
zone_->flush_txs.cancel();
|
||||
}
|
||||
|
||||
bool notify::send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, i_core_events& core, relay_method tx_relay)
|
||||
bool notify::send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, relay_method tx_relay)
|
||||
{
|
||||
if (txs.empty())
|
||||
return true;
|
||||
@@ -785,7 +819,7 @@ namespace levin
|
||||
tx_relay = relay_method::local; // do not put into stempool embargo (hopefully not there already!).
|
||||
}
|
||||
|
||||
core.on_transactions_relayed(epee::to_span(txs), tx_relay);
|
||||
core_->on_transactions_relayed(epee::to_span(txs), tx_relay);
|
||||
|
||||
// Padding is not useful when using noise mode. Send as stem so receiver
|
||||
// forwards in Dandelion++ mode.
|
||||
@@ -817,11 +851,11 @@ namespace levin
|
||||
case relay_method::stem:
|
||||
case relay_method::forward:
|
||||
case relay_method::local:
|
||||
if (zone_->is_public)
|
||||
if (zone_->nzone == epee::net_utils::zone::public_)
|
||||
{
|
||||
// this will change a local/forward tx to stem or fluff ...
|
||||
zone_->strand.dispatch(
|
||||
dandelionpp_notify{zone_, std::addressof(core), std::move(txs), source}
|
||||
dandelionpp_notify{zone_, core_, std::move(txs), source}
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -832,7 +866,7 @@ namespace levin
|
||||
routine. A "fluff" over i2p/tor is not the same as a "fluff" over
|
||||
ipv4/6. Marking it as "fluff" here will make the tx immediately
|
||||
visible externally from this node, which is not desired. */
|
||||
core.on_transactions_relayed(epee::to_span(txs), tx_relay);
|
||||
core_->on_transactions_relayed(epee::to_span(txs), tx_relay);
|
||||
zone_->strand.dispatch(fluff_notify{zone_, std::move(txs), source});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace levin
|
||||
class notify
|
||||
{
|
||||
std::shared_ptr<detail::zone> zone_;
|
||||
i_core_events* core_;
|
||||
|
||||
public:
|
||||
struct status
|
||||
@@ -80,10 +81,11 @@ namespace levin
|
||||
//! Construct an instance that cannot notify.
|
||||
notify() noexcept
|
||||
: zone_(nullptr)
|
||||
, core_(nullptr)
|
||||
{}
|
||||
|
||||
//! Construct an instance with available notification `zones`.
|
||||
explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, bool is_public, bool pad_txs);
|
||||
explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core);
|
||||
|
||||
notify(const notify&) = delete;
|
||||
notify(notify&&) = default;
|
||||
@@ -123,7 +125,7 @@ namespace levin
|
||||
particular stem.
|
||||
|
||||
\return True iff the notification is queued for sending. */
|
||||
bool send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, i_core_events& core, relay_method tx_relay);
|
||||
bool send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, relay_method tx_relay);
|
||||
};
|
||||
} // levin
|
||||
} // net
|
||||
|
||||
@@ -249,7 +249,7 @@ int main(int argc, char const * argv[])
|
||||
command_line::get_arg(vm, cryptonote::arg_data_dir));
|
||||
|
||||
#ifdef WIN32
|
||||
if (isFat32(data_dir.root_name().c_str()))
|
||||
if (isFat32(data_dir.root_path().c_str()))
|
||||
{
|
||||
MERROR("Data directory resides on FAT32 volume that has 4GiB file size limit, blockchain might get corrupted.");
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ namespace nodetool
|
||||
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
|
||||
const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy = {"tx-proxy", "Send local txes through proxy: <network-type>,<socks-ip:port>[,max_connections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\""};
|
||||
const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound = {"anonymous-inbound", "<hidden-service-address>,<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""};
|
||||
const command_line::arg_descriptor<std::string> arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
|
||||
const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false};
|
||||
|
||||
|
||||
@@ -164,6 +164,7 @@ namespace nodetool
|
||||
network_zone()
|
||||
: m_connect(nullptr),
|
||||
m_net_server(epee::net_utils::e_connection_type_P2P),
|
||||
m_seed_nodes(),
|
||||
m_bind_ip(),
|
||||
m_bind_ipv6_address(),
|
||||
m_port(),
|
||||
@@ -175,7 +176,9 @@ namespace nodetool
|
||||
m_proxy_address(),
|
||||
m_current_number_of_out_peers(0),
|
||||
m_current_number_of_in_peers(0),
|
||||
m_can_pingback(false)
|
||||
m_seed_nodes_lock(),
|
||||
m_can_pingback(false),
|
||||
m_seed_nodes_initialized(false)
|
||||
{
|
||||
set_config_defaults();
|
||||
}
|
||||
@@ -183,6 +186,7 @@ namespace nodetool
|
||||
network_zone(boost::asio::io_service& public_service)
|
||||
: m_connect(nullptr),
|
||||
m_net_server(public_service, epee::net_utils::e_connection_type_P2P),
|
||||
m_seed_nodes(),
|
||||
m_bind_ip(),
|
||||
m_bind_ipv6_address(),
|
||||
m_port(),
|
||||
@@ -194,13 +198,16 @@ namespace nodetool
|
||||
m_proxy_address(),
|
||||
m_current_number_of_out_peers(0),
|
||||
m_current_number_of_in_peers(0),
|
||||
m_can_pingback(false)
|
||||
m_seed_nodes_lock(),
|
||||
m_can_pingback(false),
|
||||
m_seed_nodes_initialized(false)
|
||||
{
|
||||
set_config_defaults();
|
||||
}
|
||||
|
||||
connect_func* m_connect;
|
||||
net_server m_net_server;
|
||||
std::vector<epee::net_utils::network_address> m_seed_nodes;
|
||||
std::string m_bind_ip;
|
||||
std::string m_bind_ipv6_address;
|
||||
std::string m_port;
|
||||
@@ -212,7 +219,9 @@ namespace nodetool
|
||||
boost::asio::ip::tcp::endpoint m_proxy_address;
|
||||
std::atomic<unsigned int> m_current_number_of_out_peers;
|
||||
std::atomic<unsigned int> m_current_number_of_in_peers;
|
||||
boost::shared_mutex m_seed_nodes_lock;
|
||||
bool m_can_pingback;
|
||||
bool m_seed_nodes_initialized;
|
||||
|
||||
private:
|
||||
void set_config_defaults() noexcept
|
||||
@@ -334,7 +343,7 @@ namespace nodetool
|
||||
virtual void callback(p2p_connection_context& context);
|
||||
//----------------- i_p2p_endpoint -------------------------------------------------------------
|
||||
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections);
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay);
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay);
|
||||
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
|
||||
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context);
|
||||
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
|
||||
@@ -383,9 +392,10 @@ namespace nodetool
|
||||
void record_addr_failed(const epee::net_utils::network_address& addr);
|
||||
bool is_addr_recently_failed(const epee::net_utils::network_address& addr);
|
||||
bool is_priority_node(const epee::net_utils::network_address& na);
|
||||
std::set<std::string> get_seed_nodes(cryptonote::network_type nettype) const;
|
||||
std::set<std::string> get_seed_nodes();
|
||||
bool connect_to_seed();
|
||||
std::set<std::string> get_ip_seed_nodes() const;
|
||||
std::set<std::string> get_dns_seed_nodes();
|
||||
std::set<std::string> get_seed_nodes(epee::net_utils::zone);
|
||||
bool connect_to_seed(epee::net_utils::zone);
|
||||
|
||||
template <class Container>
|
||||
bool connect_to_peerlist(const Container& peers);
|
||||
@@ -467,9 +477,6 @@ namespace nodetool
|
||||
|
||||
std::list<epee::net_utils::network_address> m_priority_peers;
|
||||
std::vector<epee::net_utils::network_address> m_exclusive_peers;
|
||||
std::vector<epee::net_utils::network_address> m_seed_nodes;
|
||||
bool m_seed_nodes_initialized = false;
|
||||
boost::shared_mutex m_seed_nodes_lock;
|
||||
std::atomic_flag m_fallback_seed_nodes_added;
|
||||
std::vector<nodetool::peerlist_entry> m_command_line_peers;
|
||||
uint64_t m_peer_livetime;
|
||||
@@ -523,6 +530,7 @@ namespace nodetool
|
||||
extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node;
|
||||
extern const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy;
|
||||
extern const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound;
|
||||
extern const command_line::arg_descriptor<std::string> arg_ban_list;
|
||||
extern const command_line::arg_descriptor<bool> arg_p2p_hide_my_port;
|
||||
extern const command_line::arg_descriptor<bool> arg_no_sync;
|
||||
|
||||
|
||||
@@ -71,6 +71,17 @@
|
||||
|
||||
#define MIN_WANTED_SEED_NODES 12
|
||||
|
||||
static inline boost::asio::ip::address_v4 make_address_v4_from_v6(const boost::asio::ip::address_v6& a)
|
||||
{
|
||||
const auto &bytes = a.to_bytes();
|
||||
uint32_t v4 = 0;
|
||||
v4 = (v4 << 8) | bytes[12];
|
||||
v4 = (v4 << 8) | bytes[13];
|
||||
v4 = (v4 << 8) | bytes[14];
|
||||
v4 = (v4 << 8) | bytes[15];
|
||||
return boost::asio::ip::address_v4(v4);
|
||||
}
|
||||
|
||||
namespace nodetool
|
||||
{
|
||||
template<class t_payload_net_handler>
|
||||
@@ -106,6 +117,7 @@ namespace nodetool
|
||||
command_line::add_arg(desc, arg_p2p_seed_node);
|
||||
command_line::add_arg(desc, arg_tx_proxy);
|
||||
command_line::add_arg(desc, arg_anonymous_inbound);
|
||||
command_line::add_arg(desc, arg_ban_list);
|
||||
command_line::add_arg(desc, arg_p2p_hide_my_port);
|
||||
command_line::add_arg(desc, arg_no_sync);
|
||||
command_line::add_arg(desc, arg_no_igd);
|
||||
@@ -245,6 +257,10 @@ namespace nodetool
|
||||
zone.second.m_net_server.get_config_object().close(c);
|
||||
|
||||
conns.clear();
|
||||
|
||||
peerlist_entry pe{};
|
||||
pe.adr = addr;
|
||||
zone.second.m_peerlist.remove_from_peer_white(pe);
|
||||
}
|
||||
|
||||
MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked.");
|
||||
@@ -386,7 +402,7 @@ namespace nodetool
|
||||
m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6);
|
||||
m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4);
|
||||
public_zone.m_notifier = cryptonote::levin::notify{
|
||||
public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, true, pad_txs
|
||||
public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, epee::net_utils::zone::public_, pad_txs, m_payload_handler.get_core()
|
||||
};
|
||||
|
||||
if (command_line::has_arg(vm, arg_p2p_add_peer))
|
||||
@@ -435,12 +451,42 @@ namespace nodetool
|
||||
|
||||
if (command_line::has_arg(vm, arg_p2p_seed_node))
|
||||
{
|
||||
boost::unique_lock<boost::shared_mutex> lock(m_seed_nodes_lock);
|
||||
boost::unique_lock<boost::shared_mutex> lock(public_zone.m_seed_nodes_lock);
|
||||
|
||||
if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes))
|
||||
if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, public_zone.m_seed_nodes))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!command_line::is_arg_defaulted(vm, arg_ban_list))
|
||||
{
|
||||
const std::string ban_list = command_line::get_arg(vm, arg_ban_list);
|
||||
|
||||
const boost::filesystem::path ban_list_path(ban_list);
|
||||
boost::system::error_code ec;
|
||||
if (!boost::filesystem::exists(ban_list_path, ec))
|
||||
{
|
||||
throw std::runtime_error("Can't find ban list file " + ban_list + " - " + ec.message());
|
||||
}
|
||||
|
||||
std::string banned_ips;
|
||||
if (!epee::file_io_utils::load_file_to_string(ban_list_path.string(), banned_ips))
|
||||
{
|
||||
throw std::runtime_error("Failed to read ban list file " + ban_list);
|
||||
}
|
||||
|
||||
std::istringstream iss(banned_ips);
|
||||
for (std::string line; std::getline(iss, line); )
|
||||
{
|
||||
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
|
||||
if (!parsed_addr)
|
||||
{
|
||||
MERROR("Invalid IP address: " << line << " - " << parsed_addr.error());
|
||||
continue;
|
||||
}
|
||||
block_host(*parsed_addr, std::numeric_limits<time_t>::max());
|
||||
}
|
||||
}
|
||||
|
||||
if(command_line::has_arg(vm, arg_p2p_hide_my_port))
|
||||
m_hide_my_port = true;
|
||||
|
||||
@@ -499,7 +545,7 @@ namespace nodetool
|
||||
}
|
||||
|
||||
zone.m_notifier = cryptonote::levin::notify{
|
||||
zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), false, pad_txs
|
||||
zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), proxy.zone, pad_txs, m_payload_handler.get_core()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -598,21 +644,21 @@ namespace nodetool
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(cryptonote::network_type nettype) const
|
||||
std::set<std::string> node_server<t_payload_net_handler>::get_ip_seed_nodes() const
|
||||
{
|
||||
std::set<std::string> full_addrs;
|
||||
if (nettype == cryptonote::TESTNET)
|
||||
if (m_nettype == cryptonote::TESTNET)
|
||||
{
|
||||
full_addrs.insert("212.83.175.67:28080");
|
||||
full_addrs.insert("212.83.172.165:28080");
|
||||
full_addrs.insert("192.110.160.146:28080");
|
||||
}
|
||||
else if (nettype == cryptonote::STAGENET)
|
||||
else if (m_nettype == cryptonote::STAGENET)
|
||||
{
|
||||
full_addrs.insert("162.210.173.150:38080");
|
||||
full_addrs.insert("192.110.160.146:38080");
|
||||
}
|
||||
else if (nettype == cryptonote::FAKECHAIN)
|
||||
else if (m_nettype == cryptonote::FAKECHAIN)
|
||||
{
|
||||
}
|
||||
else
|
||||
@@ -630,7 +676,7 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes()
|
||||
std::set<std::string> node_server<t_payload_net_handler>::get_dns_seed_nodes()
|
||||
{
|
||||
if (!m_exclusive_peers.empty() || m_offline)
|
||||
{
|
||||
@@ -638,11 +684,11 @@ namespace nodetool
|
||||
}
|
||||
if (m_nettype == cryptonote::TESTNET)
|
||||
{
|
||||
return get_seed_nodes(cryptonote::TESTNET);
|
||||
return get_ip_seed_nodes();
|
||||
}
|
||||
if (m_nettype == cryptonote::STAGENET)
|
||||
{
|
||||
return get_seed_nodes(cryptonote::STAGENET);
|
||||
return get_ip_seed_nodes();
|
||||
}
|
||||
|
||||
std::set<std::string> full_addrs;
|
||||
@@ -730,7 +776,7 @@ namespace nodetool
|
||||
else
|
||||
MINFO("Not enough DNS seed nodes found, using fallback defaults too");
|
||||
|
||||
for (const auto &peer: get_seed_nodes(cryptonote::MAINNET))
|
||||
for (const auto &peer: get_ip_seed_nodes())
|
||||
full_addrs.insert(peer);
|
||||
m_fallback_seed_nodes_added.test_and_set();
|
||||
}
|
||||
@@ -739,6 +785,38 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(epee::net_utils::zone zone)
|
||||
{
|
||||
switch (zone)
|
||||
{
|
||||
case epee::net_utils::zone::public_:
|
||||
return get_dns_seed_nodes();
|
||||
case epee::net_utils::zone::tor:
|
||||
if (m_nettype == cryptonote::MAINNET)
|
||||
{
|
||||
return {
|
||||
"xwvz3ekocr3dkyxfkmgm2hvbpzx2ysqmaxgter7znnqrhoicygkfswid.onion:18083",
|
||||
"4pixvbejrvihnkxmduo2agsnmc3rrulrqc7s3cbwwrep6h6hrzsibeqd.onion:18083",
|
||||
"zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083"
|
||||
};
|
||||
}
|
||||
return {};
|
||||
case epee::net_utils::zone::i2p:
|
||||
if (m_nettype == cryptonote::MAINNET)
|
||||
{
|
||||
return {
|
||||
"s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080",
|
||||
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080"
|
||||
};
|
||||
}
|
||||
return {};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::logic_error{"Bad zone given to get_seed_nodes"};
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
typename node_server<t_payload_net_handler>::network_zone& node_server<t_payload_net_handler>::add_zone(const epee::net_utils::zone zone)
|
||||
{
|
||||
const auto zone_ = m_network_zones.lower_bound(zone);
|
||||
@@ -1232,7 +1310,13 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp)
|
||||
{
|
||||
network_zone& zone = m_network_zones.at(na.get_zone());
|
||||
const auto i = m_network_zones.find(na.get_zone());
|
||||
if (i == m_network_zones.end())
|
||||
{
|
||||
MERROR("Tried connecting to address for disabled network");
|
||||
return false;
|
||||
}
|
||||
network_zone& zone = i->second;
|
||||
if (zone.m_connect == nullptr) // outgoing connections in zone not possible
|
||||
return false;
|
||||
|
||||
@@ -1432,17 +1516,44 @@ namespace nodetool
|
||||
const uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
|
||||
classB.insert(actual_ip & 0x0000ffff);
|
||||
}
|
||||
else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
|
||||
{
|
||||
const epee::net_utils::network_address na = cntxt.m_remote_address;
|
||||
const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
|
||||
if (actual_ip.is_v4_mapped())
|
||||
{
|
||||
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
|
||||
uint32_t actual_ipv4;
|
||||
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
|
||||
classB.insert(actual_ipv4 & ntohl(0xffff0000));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
auto get_host_string = [](const epee::net_utils::network_address &address) {
|
||||
if (address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
|
||||
{
|
||||
boost::asio::ip::address_v6 actual_ip = address.as<const epee::net_utils::ipv6_network_address>().ip();
|
||||
if (actual_ip.is_v4_mapped())
|
||||
{
|
||||
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
|
||||
uint32_t actual_ipv4;
|
||||
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
|
||||
return epee::net_utils::ipv4_network_address(actual_ipv4, 0).host_str();
|
||||
}
|
||||
}
|
||||
return address.host_str();
|
||||
};
|
||||
std::unordered_set<std::string> hosts_added;
|
||||
std::deque<size_t> filtered;
|
||||
const size_t limit = use_white_list ? 20 : std::numeric_limits<size_t>::max();
|
||||
for (int step = 0; step < 2; ++step)
|
||||
{
|
||||
bool skip_duplicate_class_B = step == 0;
|
||||
size_t idx = 0, skipped = 0;
|
||||
zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe](const peerlist_entry &pe){
|
||||
zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe, &hosts_added, &get_host_string](const peerlist_entry &pe){
|
||||
if (filtered.size() >= limit)
|
||||
return false;
|
||||
bool skip = false;
|
||||
@@ -1452,6 +1563,27 @@ namespace nodetool
|
||||
uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
|
||||
skip = classB.find(actual_ip & 0x0000ffff) != classB.end();
|
||||
}
|
||||
else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
|
||||
{
|
||||
const epee::net_utils::network_address na = pe.adr;
|
||||
const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
|
||||
if (actual_ip.is_v4_mapped())
|
||||
{
|
||||
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
|
||||
uint32_t actual_ipv4;
|
||||
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
|
||||
skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end();
|
||||
}
|
||||
}
|
||||
|
||||
// consider each host once, to avoid giving undue inflence to hosts running several nodes
|
||||
if (!skip)
|
||||
{
|
||||
const auto i = hosts_added.find(get_host_string(pe.adr));
|
||||
if (i != hosts_added.end())
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
++skipped;
|
||||
else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0)
|
||||
@@ -1459,16 +1591,17 @@ namespace nodetool
|
||||
else if (next_needed_pruning_stripe == tools::get_pruning_stripe(pe.pruning_seed))
|
||||
filtered.push_front(idx);
|
||||
++idx;
|
||||
hosts_added.insert(get_host_string(pe.adr));
|
||||
return true;
|
||||
});
|
||||
if (skipped == 0 || !filtered.empty())
|
||||
break;
|
||||
if (skipped)
|
||||
MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers");
|
||||
MDEBUG("Skipping " << skipped << " possible peers as they share a class B with existing peers");
|
||||
}
|
||||
if (filtered.empty())
|
||||
{
|
||||
MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
|
||||
MINFO("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
|
||||
return false;
|
||||
}
|
||||
if (use_white_list)
|
||||
@@ -1541,56 +1674,59 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::connect_to_seed()
|
||||
bool node_server<t_payload_net_handler>::connect_to_seed(epee::net_utils::zone zone)
|
||||
{
|
||||
boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(m_seed_nodes_lock);
|
||||
network_zone& server = m_network_zones.at(zone);
|
||||
boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(server.m_seed_nodes_lock);
|
||||
|
||||
if (!m_seed_nodes_initialized)
|
||||
if (!server.m_seed_nodes_initialized)
|
||||
{
|
||||
const std::uint16_t default_port = cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT;
|
||||
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
|
||||
m_seed_nodes_initialized = true;
|
||||
for (const auto& full_addr : get_seed_nodes())
|
||||
server.m_seed_nodes_initialized = true;
|
||||
for (const auto& full_addr : get_seed_nodes(zone))
|
||||
{
|
||||
// seeds should have hostname converted to IP already
|
||||
MDEBUG("Seed node: " << full_addr);
|
||||
append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
|
||||
server.m_seed_nodes.push_back(MONERO_UNWRAP(net::get_network_address(full_addr, default_port)));
|
||||
}
|
||||
MDEBUG("Number of seed nodes: " << m_seed_nodes.size());
|
||||
MDEBUG("Number of seed nodes: " << server.m_seed_nodes.size());
|
||||
}
|
||||
|
||||
if (m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
|
||||
if (server.m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
|
||||
return true;
|
||||
|
||||
size_t try_count = 0;
|
||||
bool is_connected_to_at_least_one_seed_node = false;
|
||||
size_t current_index = crypto::rand_idx(m_seed_nodes.size());
|
||||
const net_server& server = m_network_zones.at(epee::net_utils::zone::public_).m_net_server;
|
||||
size_t current_index = crypto::rand_idx(server.m_seed_nodes.size());
|
||||
while(true)
|
||||
{
|
||||
if(server.is_stop_signal_sent())
|
||||
if(server.m_net_server.is_stop_signal_sent())
|
||||
return false;
|
||||
|
||||
peerlist_entry pe_seed{};
|
||||
pe_seed.adr = m_seed_nodes[current_index];
|
||||
pe_seed.adr = server.m_seed_nodes[current_index];
|
||||
if (is_peer_used(pe_seed))
|
||||
is_connected_to_at_least_one_seed_node = true;
|
||||
else if (try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true))
|
||||
else if (try_to_connect_and_handshake_with_new_peer(server.m_seed_nodes[current_index], true))
|
||||
break;
|
||||
if(++try_count > m_seed_nodes.size())
|
||||
if(++try_count > server.m_seed_nodes.size())
|
||||
{
|
||||
if (!m_fallback_seed_nodes_added.test_and_set())
|
||||
// only IP zone has fallback (to direct IP) seeds
|
||||
if (zone == epee::net_utils::zone::public_ && !m_fallback_seed_nodes_added.test_and_set())
|
||||
{
|
||||
MWARNING("Failed to connect to any of seed peers, trying fallback seeds");
|
||||
current_index = m_seed_nodes.size() - 1;
|
||||
current_index = server.m_seed_nodes.size() - 1;
|
||||
{
|
||||
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
|
||||
|
||||
for (const auto &peer: get_seed_nodes(m_nettype))
|
||||
for (const auto &peer: get_ip_seed_nodes())
|
||||
{
|
||||
MDEBUG("Fallback seed node: " << peer);
|
||||
append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
|
||||
append_net_address(server.m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
|
||||
}
|
||||
}
|
||||
if (current_index == m_seed_nodes.size() - 1)
|
||||
if (current_index == server.m_seed_nodes.size() - 1)
|
||||
{
|
||||
MWARNING("No fallback seeds, continuing without seeds");
|
||||
break;
|
||||
@@ -1604,7 +1740,7 @@ namespace nodetool
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(++current_index >= m_seed_nodes.size())
|
||||
if(++current_index >= server.m_seed_nodes.size())
|
||||
current_index = 0;
|
||||
}
|
||||
return true;
|
||||
@@ -1620,20 +1756,21 @@ namespace nodetool
|
||||
|
||||
if (!m_exclusive_peers.empty()) return true;
|
||||
|
||||
// Only have seeds in the public zone right now.
|
||||
|
||||
size_t start_conn_count = get_public_outgoing_connections_count();
|
||||
if(!get_public_white_peers_count() && !connect_to_seed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!connect_to_peerlist(m_priority_peers)) return false;
|
||||
|
||||
bool one_succeeded = false;
|
||||
for(auto& zone : m_network_zones)
|
||||
{
|
||||
size_t start_conn_count = get_outgoing_connections_count(zone.second);
|
||||
if(!zone.second.m_peerlist.get_white_peers_count() && !connect_to_seed(zone.first))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zone.first == zone_type::public_ && !connect_to_peerlist(m_priority_peers)) continue;
|
||||
|
||||
size_t base_expected_white_connections = (zone.second.m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
|
||||
|
||||
// carefully avoid `continue` in nested loop
|
||||
|
||||
size_t conn_count = get_outgoing_connections_count(zone.second);
|
||||
while(conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
|
||||
{
|
||||
@@ -1670,16 +1807,17 @@ namespace nodetool
|
||||
}
|
||||
conn_count = new_conn_count;
|
||||
}
|
||||
|
||||
if (start_conn_count == get_outgoing_connections_count(zone.second) && start_conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
|
||||
{
|
||||
MINFO("Failed to connect to any, trying seeds");
|
||||
if (!connect_to_seed(zone.first))
|
||||
continue;
|
||||
}
|
||||
one_succeeded = true;
|
||||
}
|
||||
|
||||
if (start_conn_count == get_public_outgoing_connections_count() && start_conn_count < m_network_zones.at(zone_type::public_).m_config.m_net_config.max_out_connection_count)
|
||||
{
|
||||
MINFO("Failed to connect to any, trying seeds");
|
||||
if (!connect_to_seed())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return one_succeeded;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
@@ -1994,13 +2132,13 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, const cryptonote::relay_method tx_relay)
|
||||
epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const cryptonote::relay_method tx_relay)
|
||||
{
|
||||
namespace enet = epee::net_utils;
|
||||
|
||||
const auto send = [&txs, &source, &core, tx_relay] (std::pair<const enet::zone, network_zone>& network)
|
||||
const auto send = [&txs, &source, tx_relay] (std::pair<const enet::zone, network_zone>& network)
|
||||
{
|
||||
if (network.second.m_notifier.send_txs(std::move(txs), source, core, tx_relay))
|
||||
if (network.second.m_notifier.send_txs(std::move(txs), source, tx_relay))
|
||||
return network.first;
|
||||
return enet::zone::invalid;
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace nodetool
|
||||
struct i_p2p_endpoint
|
||||
{
|
||||
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0;
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay)=0;
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay)=0;
|
||||
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
|
||||
@@ -75,7 +75,7 @@ namespace nodetool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay)
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay)
|
||||
{
|
||||
return epee::net_utils::zone::invalid;
|
||||
}
|
||||
|
||||
@@ -368,6 +368,12 @@ namespace rct {
|
||||
template<bool W, template <bool> class Archive>
|
||||
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
|
||||
{
|
||||
if (inputs >= 0xffffffff)
|
||||
return false;
|
||||
if (outputs >= 0xffffffff)
|
||||
return false;
|
||||
if (mixin >= 0xffffffff)
|
||||
return false;
|
||||
if (type == RCTTypeNull)
|
||||
return ar.stream().good();
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG)
|
||||
|
||||
@@ -45,12 +45,12 @@ namespace cryptonote
|
||||
return host + ":" + m_http_client.get_port();
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> bootstrap_daemon::get_height()
|
||||
boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon::get_height()
|
||||
{
|
||||
cryptonote::COMMAND_RPC_GET_HEIGHT::request req;
|
||||
cryptonote::COMMAND_RPC_GET_HEIGHT::response res;
|
||||
cryptonote::COMMAND_RPC_GET_INFO::request req;
|
||||
cryptonote::COMMAND_RPC_GET_INFO::response res;
|
||||
|
||||
if (!invoke_http_json("/getheight", req, res))
|
||||
if (!invoke_http_json("/getinfo", req, res))
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ namespace cryptonote
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
return res.height;
|
||||
return {{res.height, res.target_height}};
|
||||
}
|
||||
|
||||
bool bootstrap_daemon::handle_result(bool success, const std::string &status)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
@@ -27,7 +28,7 @@ namespace cryptonote
|
||||
bool rpc_payment_enabled);
|
||||
|
||||
std::string address() const noexcept;
|
||||
boost::optional<uint64_t> get_height();
|
||||
boost::optional<std::pair<uint64_t, uint64_t>> get_height();
|
||||
bool handle_result(bool success, const std::string &status);
|
||||
|
||||
template <class t_request, class t_response>
|
||||
|
||||
@@ -521,9 +521,17 @@ namespace cryptonote
|
||||
bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(get_blocks);
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r))
|
||||
return r;
|
||||
|
||||
bool use_bootstrap_daemon;
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
|
||||
use_bootstrap_daemon = m_should_use_bootstrap_daemon;
|
||||
}
|
||||
if (use_bootstrap_daemon)
|
||||
{
|
||||
bool r;
|
||||
return use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r);
|
||||
}
|
||||
|
||||
CHECK_PAYMENT(req, res, 1);
|
||||
|
||||
@@ -1123,6 +1131,11 @@ namespace cryptonote
|
||||
{
|
||||
RPC_TRACKER(send_raw_tx);
|
||||
|
||||
{
|
||||
bool ok;
|
||||
use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok);
|
||||
}
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
|
||||
bool skip_validation = false;
|
||||
@@ -1138,6 +1151,10 @@ namespace cryptonote
|
||||
CHECK_CORE_READY();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_CORE_READY();
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_RELAY, false);
|
||||
|
||||
@@ -1661,6 +1678,13 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t next_height;
|
||||
crypto::rx_seedheights(height, &seed_height, &next_height);
|
||||
if (next_height != seed_height)
|
||||
next_seed_hash = m_core.get_block_id_by_height(next_height);
|
||||
else
|
||||
next_seed_hash = seed_hash;
|
||||
|
||||
if (extra_nonce.empty())
|
||||
{
|
||||
reserved_offset = 0;
|
||||
@@ -1967,34 +1991,37 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
if (!m_p2p.get_payload_object().no_sync() &&
|
||||
current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
|
||||
if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
|
||||
{
|
||||
{
|
||||
boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock);
|
||||
m_bootstrap_height_check_time = current_time;
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> bootstrap_daemon_height = m_bootstrap_daemon->get_height();
|
||||
if (!bootstrap_daemon_height)
|
||||
boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon_height_info = m_bootstrap_daemon->get_height();
|
||||
if (!bootstrap_daemon_height_info)
|
||||
{
|
||||
MERROR("Failed to fetch bootstrap daemon height");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t target_height = m_core.get_target_blockchain_height();
|
||||
if (*bootstrap_daemon_height < target_height)
|
||||
const uint64_t bootstrap_daemon_height = bootstrap_daemon_height_info->first;
|
||||
const uint64_t bootstrap_daemon_target_height = bootstrap_daemon_height_info->second;
|
||||
if (bootstrap_daemon_height < bootstrap_daemon_target_height)
|
||||
{
|
||||
MINFO("Bootstrap daemon is out of sync");
|
||||
return m_bootstrap_daemon->handle_result(false, {});
|
||||
}
|
||||
|
||||
uint64_t top_height = m_core.get_current_blockchain_height();
|
||||
m_should_use_bootstrap_daemon = top_height + 10 < *bootstrap_daemon_height;
|
||||
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << *bootstrap_daemon_height << ")");
|
||||
if (!m_p2p.get_payload_object().no_sync())
|
||||
{
|
||||
uint64_t top_height = m_core.get_current_blockchain_height();
|
||||
m_should_use_bootstrap_daemon = top_height + 10 < bootstrap_daemon_height;
|
||||
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << bootstrap_daemon_height << ")");
|
||||
|
||||
if (!m_should_use_bootstrap_daemon)
|
||||
return false;
|
||||
if (!m_should_use_bootstrap_daemon)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == invoke_http_mode::JON)
|
||||
@@ -2812,6 +2839,8 @@ namespace cryptonote
|
||||
RPC_TRACKER(relay_tx);
|
||||
CHECK_PAYMENT_MIN1(req, res, req.txids.size() * COST_PER_TX_RELAY, false);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
|
||||
bool failed = false;
|
||||
res.status = "";
|
||||
for (const auto &str: req.txids)
|
||||
@@ -2825,12 +2854,16 @@ namespace cryptonote
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO: The get_pool_transaction could have an optional meta parameter
|
||||
bool broadcasted = false;
|
||||
cryptonote::blobdata txblob;
|
||||
if (m_core.get_pool_transaction(txid, txblob, relay_category::legacy))
|
||||
if ((broadcasted = m_core.get_pool_transaction(txid, txblob, relay_category::broadcasted)) || (!restricted && m_core.get_pool_transaction(txid, txblob, relay_category::all)))
|
||||
{
|
||||
// The settings below always choose i2p/tor if enabled. Otherwise, do fluff iff previously relayed else dandelion++ stem.
|
||||
NOTIFY_NEW_TRANSACTIONS::request r;
|
||||
r.txs.push_back(std::move(txblob));
|
||||
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, relay_method::local);
|
||||
const auto tx_relay = broadcasted ? relay_method::fluff : relay_method::local;
|
||||
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, tx_relay);
|
||||
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_MONERO_VERSION "0.17.0.0"
|
||||
#define DEF_MONERO_VERSION "0.17.1.5"
|
||||
#define DEF_MONERO_RELEASE_NAME "Oxygen Orion"
|
||||
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
|
||||
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@
|
||||
|
||||
@@ -910,6 +910,11 @@ std::string WalletImpl::path() const
|
||||
return m_wallet->path();
|
||||
}
|
||||
|
||||
void WalletImpl::stop()
|
||||
{
|
||||
m_wallet->stop();
|
||||
}
|
||||
|
||||
bool WalletImpl::store(const std::string &path)
|
||||
{
|
||||
clearStatus();
|
||||
|
||||
@@ -99,6 +99,7 @@ public:
|
||||
std::string publicSpendKey() const override;
|
||||
std::string publicMultisigSignerKey() const override;
|
||||
std::string path() const override;
|
||||
void stop() override;
|
||||
bool store(const std::string &path) override;
|
||||
std::string filename() const override;
|
||||
std::string keysFilename() const override;
|
||||
|
||||
@@ -506,6 +506,11 @@ struct Wallet
|
||||
*/
|
||||
virtual std::string publicMultisigSignerKey() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief stop - interrupts wallet refresh() loop once (doesn't stop background refresh thread)
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
|
||||
/*!
|
||||
* \brief store - stores wallet to file.
|
||||
* \param path - main filename to store wallet to. additionally stores address file and keys file.
|
||||
|
||||
@@ -2961,6 +2961,8 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
|
||||
MTRACE("update_pool_state got pool");
|
||||
|
||||
// remove any pending tx that's not in the pool
|
||||
constexpr const std::chrono::seconds tx_propagation_timeout{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2};
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin();
|
||||
while (it != m_unconfirmed_txs.end())
|
||||
{
|
||||
@@ -2988,9 +2990,11 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
|
||||
LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as not in pool");
|
||||
pit->second.m_state = wallet2::unconfirmed_transfer_details::pending_not_in_pool;
|
||||
}
|
||||
else if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending_not_in_pool && refreshed)
|
||||
else if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending_not_in_pool && refreshed &&
|
||||
now > std::chrono::system_clock::from_time_t(pit->second.m_sent_time) + tx_propagation_timeout)
|
||||
{
|
||||
LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as failed");
|
||||
LOG_PRINT_L1("Pending txid " << txid << " not in pool after " << tx_propagation_timeout.count() <<
|
||||
" seconds, marking as failed");
|
||||
pit->second.m_state = wallet2::unconfirmed_transfer_details::failed;
|
||||
|
||||
// the inputs aren't spent anymore, since the tx failed
|
||||
@@ -13043,6 +13047,8 @@ process:
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
|
||||
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_internal_output_index >= td.m_tx.vout.size(),
|
||||
error::wallet_internal_error, "Internal index is out of range");
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_tx.vout[td.m_internal_output_index].target.type() != typeid(cryptonote::txout_to_key),
|
||||
error::wallet_internal_error, "Unsupported output type");
|
||||
const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
|
||||
@@ -13375,6 +13381,20 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs)
|
||||
loaded = true;
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(loaded, "Failed to load output data");
|
||||
|
||||
for (const auto &e: i)
|
||||
{
|
||||
for (const auto &lr: e.m_LR)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(lr.m_L), "Multisig value is not in the main subgroup");
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(lr.m_R), "Multisig value is not in the main subgroup");
|
||||
}
|
||||
for (const auto &ki: e.m_partial_key_images)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(rct::ki2rct(ki)), "Multisig partial key image is not in the main subgroup");
|
||||
}
|
||||
}
|
||||
|
||||
MINFO(boost::format("%u outputs found") % boost::lexical_cast<std::string>(i.size()));
|
||||
info.push_back(std::move(i));
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ private:
|
||||
std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> m_rings; // relative
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VERSION_FIELD(0)
|
||||
VERSION_FIELD(1)
|
||||
FIELD(m_tx)
|
||||
VARINT_FIELD(m_amount_in)
|
||||
VARINT_FIELD(m_amount_out)
|
||||
@@ -442,6 +442,8 @@ private:
|
||||
VARINT_FIELD(m_sent_time)
|
||||
FIELD(m_dests)
|
||||
FIELD(m_payment_id)
|
||||
if (version >= 1)
|
||||
VARINT_FIELD(m_state)
|
||||
VARINT_FIELD(m_timestamp)
|
||||
VARINT_FIELD(m_subaddr_account)
|
||||
FIELD(m_subaddr_indices)
|
||||
|
||||
@@ -66,9 +66,10 @@ namespace tests
|
||||
|
||||
|
||||
public:
|
||||
virtual bool is_synchronized() const final { return true; }
|
||||
void on_synchronized(){}
|
||||
void safesyncmode(const bool){}
|
||||
uint64_t get_current_blockchain_height(){return 1;}
|
||||
virtual uint64_t get_current_blockchain_height() const final {return 1;}
|
||||
void set_target_blockchain_height(uint64_t) {}
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
bool deinit(){return true;}
|
||||
|
||||
@@ -120,6 +120,16 @@ namespace
|
||||
{
|
||||
std::map<cryptonote::relay_method, std::vector<cryptonote::blobdata>> relayed_;
|
||||
|
||||
virtual bool is_synchronized() const final
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual uint64_t get_current_blockchain_height() const final
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> txes, cryptonote::relay_method relay) override final
|
||||
{
|
||||
std::vector<cryptonote::blobdata>& cached = relayed_[relay];
|
||||
@@ -324,7 +334,8 @@ namespace
|
||||
epee::byte_slice noise = nullptr;
|
||||
if (noise_size)
|
||||
noise = epee::levin::make_noise_notify(noise_size);
|
||||
return cryptonote::levin::notify{io_service_, connections_, std::move(noise), is_public, pad_txs};
|
||||
epee::net_utils::zone zone = is_public ? epee::net_utils::zone::public_ : epee::net_utils::zone::i2p;
|
||||
return cryptonote::levin::notify{io_service_, connections_, std::move(noise), zone, pad_txs, events_};
|
||||
}
|
||||
|
||||
boost::uuids::random_generator random_generator_;
|
||||
@@ -483,11 +494,11 @@ TEST_F(levin_notify, defaulted)
|
||||
EXPECT_FALSE(status.has_noise);
|
||||
EXPECT_FALSE(status.connections_filled);
|
||||
}
|
||||
EXPECT_TRUE(notifier.send_txs({}, random_generator_(), events_, cryptonote::relay_method::local));
|
||||
EXPECT_TRUE(notifier.send_txs({}, random_generator_(), cryptonote::relay_method::local));
|
||||
|
||||
std::vector<cryptonote::blobdata> txs(2);
|
||||
txs[0].resize(100, 'e');
|
||||
EXPECT_FALSE(notifier.send_txs(std::move(txs), random_generator_(), events_, cryptonote::relay_method::local));
|
||||
EXPECT_FALSE(notifier.send_txs(std::move(txs), random_generator_(), cryptonote::relay_method::local));
|
||||
}
|
||||
|
||||
TEST_F(levin_notify, fluff_without_padding)
|
||||
@@ -512,7 +523,7 @@ TEST_F(levin_notify, fluff_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -564,7 +575,7 @@ TEST_F(levin_notify, stem_without_padding)
|
||||
while (!has_stemmed || !has_fluffed)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -608,6 +619,61 @@ TEST_F(levin_notify, stem_without_padding)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(levin_notify, stem_no_outs_without_padding)
|
||||
{
|
||||
cryptonote::levin::notify notifier = make_notifier(0, true, false);
|
||||
|
||||
for (unsigned count = 0; count < 10; ++count)
|
||||
add_connection(true);
|
||||
|
||||
{
|
||||
const auto status = notifier.get_status();
|
||||
EXPECT_FALSE(status.has_noise);
|
||||
EXPECT_FALSE(status.connections_filled);
|
||||
}
|
||||
notifier.new_out_connection();
|
||||
io_service_.poll();
|
||||
|
||||
std::vector<cryptonote::blobdata> txs(2);
|
||||
txs[0].resize(100, 'f');
|
||||
txs[1].resize(200, 'e');
|
||||
|
||||
std::vector<cryptonote::blobdata> sorted_txs = txs;
|
||||
std::sort(sorted_txs.begin(), sorted_txs.end());
|
||||
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
|
||||
if (events_.has_stem_txes())
|
||||
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
|
||||
|
||||
|
||||
notifier.run_fluff();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
|
||||
std::size_t send_count = 0;
|
||||
EXPECT_EQ(0u, context->process_send_queue());
|
||||
for (++context; context != contexts_.end(); ++context)
|
||||
{
|
||||
send_count += context->process_send_queue();
|
||||
}
|
||||
|
||||
EXPECT_EQ(9u, send_count);
|
||||
ASSERT_EQ(9u, receiver_.notified_size());
|
||||
for (unsigned count = 0; count < 9u; ++count)
|
||||
{
|
||||
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
|
||||
EXPECT_EQ(sorted_txs, notification.txs);
|
||||
EXPECT_TRUE(notification._.empty());
|
||||
EXPECT_TRUE(notification.dandelionpp_fluff);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(levin_notify, local_without_padding)
|
||||
{
|
||||
cryptonote::levin::notify notifier = make_notifier(0, true, false);
|
||||
@@ -636,7 +702,7 @@ TEST_F(levin_notify, local_without_padding)
|
||||
while (!has_stemmed || !has_fluffed)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -708,7 +774,7 @@ TEST_F(levin_notify, forward_without_padding)
|
||||
while (!has_stemmed || !has_fluffed)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -727,7 +793,9 @@ TEST_F(levin_notify, forward_without_padding)
|
||||
{
|
||||
const std::size_t sent = context->process_send_queue();
|
||||
if (sent && is_stem)
|
||||
{
|
||||
EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
|
||||
}
|
||||
send_count += sent;
|
||||
}
|
||||
|
||||
@@ -772,7 +840,7 @@ TEST_F(levin_notify, block_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -801,7 +869,7 @@ TEST_F(levin_notify, none_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -830,7 +898,7 @@ TEST_F(levin_notify, fluff_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -879,7 +947,7 @@ TEST_F(levin_notify, stem_with_padding)
|
||||
while (!has_stemmed || !has_fluffed)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -921,6 +989,60 @@ TEST_F(levin_notify, stem_with_padding)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(levin_notify, stem_no_outs_with_padding)
|
||||
{
|
||||
cryptonote::levin::notify notifier = make_notifier(0, true, true);
|
||||
|
||||
for (unsigned count = 0; count < 10; ++count)
|
||||
add_connection(true);
|
||||
|
||||
{
|
||||
const auto status = notifier.get_status();
|
||||
EXPECT_FALSE(status.has_noise);
|
||||
EXPECT_FALSE(status.connections_filled);
|
||||
}
|
||||
notifier.new_out_connection();
|
||||
io_service_.poll();
|
||||
|
||||
std::vector<cryptonote::blobdata> txs(2);
|
||||
txs[0].resize(100, 'f');
|
||||
txs[1].resize(200, 'e');
|
||||
|
||||
std::vector<cryptonote::blobdata> sorted_txs = txs;
|
||||
std::sort(sorted_txs.begin(), sorted_txs.end());
|
||||
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
|
||||
if (events_.has_stem_txes())
|
||||
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
|
||||
|
||||
notifier.run_fluff();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
|
||||
std::size_t send_count = 0;
|
||||
EXPECT_EQ(0u, context->process_send_queue());
|
||||
for (++context; context != contexts_.end(); ++context)
|
||||
{
|
||||
send_count += context->process_send_queue();
|
||||
}
|
||||
|
||||
EXPECT_EQ(9u, send_count);
|
||||
ASSERT_EQ(9u, receiver_.notified_size());
|
||||
for (unsigned count = 0; count < 9u; ++count)
|
||||
{
|
||||
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
|
||||
EXPECT_EQ(sorted_txs, notification.txs);
|
||||
EXPECT_FALSE(notification._.empty());
|
||||
EXPECT_TRUE(notification.dandelionpp_fluff);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(levin_notify, local_with_padding)
|
||||
{
|
||||
cryptonote::levin::notify notifier = make_notifier(0, true, true);
|
||||
@@ -946,7 +1068,7 @@ TEST_F(levin_notify, local_with_padding)
|
||||
while (!has_stemmed || !has_fluffed)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1013,7 +1135,7 @@ TEST_F(levin_notify, forward_with_padding)
|
||||
while (!has_stemmed || !has_fluffed)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1077,7 +1199,7 @@ TEST_F(levin_notify, block_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -1106,7 +1228,7 @@ TEST_F(levin_notify, none_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -1135,7 +1257,7 @@ TEST_F(levin_notify, private_fluff_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1186,7 +1308,7 @@ TEST_F(levin_notify, private_stem_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1237,7 +1359,7 @@ TEST_F(levin_notify, private_local_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1288,7 +1410,7 @@ TEST_F(levin_notify, private_forward_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1339,7 +1461,7 @@ TEST_F(levin_notify, private_block_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -1369,7 +1491,7 @@ TEST_F(levin_notify, private_none_without_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -1398,7 +1520,7 @@ TEST_F(levin_notify, private_fluff_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1448,7 +1570,7 @@ TEST_F(levin_notify, private_stem_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1498,7 +1620,7 @@ TEST_F(levin_notify, private_local_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1548,7 +1670,7 @@ TEST_F(levin_notify, private_forward_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1598,7 +1720,7 @@ TEST_F(levin_notify, private_block_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -1627,7 +1749,7 @@ TEST_F(levin_notify, private_none_with_padding)
|
||||
ASSERT_EQ(10u, contexts_.size());
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
|
||||
EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_EQ(0u, io_service_.poll());
|
||||
@@ -1659,7 +1781,7 @@ TEST_F(levin_notify, stem_mappings)
|
||||
for (;;)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1721,7 +1843,7 @@ TEST_F(levin_notify, stem_mappings)
|
||||
for (unsigned i = 0; i < contexts_.size() * 2; i += 2)
|
||||
{
|
||||
auto& incoming = contexts_[i % contexts_.size()];
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1782,7 +1904,7 @@ TEST_F(levin_notify, fluff_multiple)
|
||||
for (;;)
|
||||
{
|
||||
auto context = contexts_.begin();
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1841,7 +1963,7 @@ TEST_F(levin_notify, fluff_multiple)
|
||||
for (unsigned i = 0; i < contexts_.size() * 2; i += 2)
|
||||
{
|
||||
auto& incoming = contexts_[i % contexts_.size()];
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), cryptonote::relay_method::stem));
|
||||
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1905,7 +2027,7 @@ TEST_F(levin_notify, noise)
|
||||
EXPECT_EQ(0u, receiver_.notified_size());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::local));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming_id, cryptonote::relay_method::local));
|
||||
notifier.run_stems();
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1927,7 +2049,7 @@ TEST_F(levin_notify, noise)
|
||||
}
|
||||
|
||||
txs[0].resize(3000, 'r');
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::fluff));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming_id, cryptonote::relay_method::fluff));
|
||||
notifier.run_stems();
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
@@ -1996,7 +2118,7 @@ TEST_F(levin_notify, noise_stem)
|
||||
EXPECT_EQ(0u, receiver_.notified_size());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::stem));
|
||||
EXPECT_TRUE(notifier.send_txs(txs, incoming_id, cryptonote::relay_method::stem));
|
||||
notifier.run_stems();
|
||||
io_service_.reset();
|
||||
ASSERT_LT(0u, io_service_.poll());
|
||||
|
||||
@@ -47,9 +47,10 @@ namespace cryptonote {
|
||||
class test_core : public cryptonote::i_core_events
|
||||
{
|
||||
public:
|
||||
virtual bool is_synchronized() const final { return true; }
|
||||
void on_synchronized(){}
|
||||
void safesyncmode(const bool){}
|
||||
uint64_t get_current_blockchain_height() const {return 1;}
|
||||
virtual uint64_t get_current_blockchain_height() const final {return 1;}
|
||||
void set_target_blockchain_height(uint64_t) {}
|
||||
bool init(const boost::program_options::variables_map& vm) {return true ;}
|
||||
bool deinit(){return true;}
|
||||
|
||||
Reference in New Issue
Block a user