15#include <boost/test/unit_test.hpp>
17using namespace std::string_literals;
26 auto apply_random_xor_chunks{[&](std::span<std::byte> target,
const Obfuscation& obfuscation) {
27 for (
size_t offset{0}; offset < target.size();) {
28 const size_t chunk_size{1 + m_rng.randrange(target.size() - offset)};
29 obfuscation(target.subspan(offset, chunk_size), offset);
34 for (
size_t test{0}; test < 100; ++test) {
35 const size_t write_size{1 + m_rng.randrange(100U)};
36 const std::vector original{m_rng.randbytes<std::byte>(write_size)};
37 std::vector roundtrip{original};
39 const auto key_bytes{m_rng.randbool() ? m_rng.randbytes<
Obfuscation::KEY_SIZE>() : std::array<std::byte, Obfuscation::KEY_SIZE>{}};
41 apply_random_xor_chunks(roundtrip, obfuscation);
43 for (
size_t i{0}; i < original.size(); ++i) {
47 apply_random_xor_chunks(roundtrip, obfuscation);
73 std::vector<std::byte> key_out;
75 ds_out << obfuscation;
87 const Obfuscation non_null_obf{
"ff00ff00ff00ff00"_hex};
93 fs::path xor_path{m_args.GetDataDirBase() /
"test_xor.bin"};
94 auto raw_file{[&](
const auto& mode) {
return fsbridge::fopen(xor_path, mode); }};
95 const std::vector<uint8_t>
test1{1, 2, 3};
96 const std::vector<uint8_t> test2{4, 5};
97 const Obfuscation obfuscation{
"ff00ff00ff00ff00"_hex};
101 AutoFile xor_file{raw_file(
"rb"), obfuscation};
102 BOOST_CHECK_EXCEPTION(xor_file << std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::write: file handle is nullptr"});
103 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: file handle is nullptr"});
104 BOOST_CHECK_EXCEPTION(xor_file.
ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: file handle is nullptr"});
105 BOOST_CHECK_EXCEPTION(xor_file.
size(), std::ios_base::failure,
HasReason{
"AutoFile::size: file handle is nullptr"});
110 const char* mode =
"wb";
112 const char* mode =
"wbx";
114 AutoFile xor_file{raw_file(mode), obfuscation};
115 xor_file <<
test1 << test2;
117 BOOST_REQUIRE_EQUAL(xor_file.
fclose(), 0);
121 AutoFile non_xor_file{raw_file(
"rb")};
122 std::vector<std::byte> raw(7);
123 non_xor_file >> std::span{raw};
126 BOOST_CHECK_EXCEPTION(non_xor_file.
ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
130 AutoFile xor_file{raw_file(
"rb"), obfuscation};
131 std::vector<std::byte> read1, read2;
132 xor_file >> read1 >> read2;
136 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
140 AutoFile xor_file{raw_file(
"rb"), obfuscation};
141 std::vector<std::byte> read2;
147 BOOST_CHECK_EXCEPTION(xor_file.
ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
148 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
157 unsigned char bytes[] = {3, 4, 5, 6};
158 std::vector<unsigned char> vch;
165 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
167 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
171 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
173 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
178 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
180 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
185 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
187 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
192 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
194 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
198 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
200 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
205 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
207 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
213 std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
258 std::vector<uint8_t> data{0x82, 0xa7, 0x31};
272 bit_writer.
Write(0, 1);
273 bit_writer.
Write(2, 2);
274 bit_writer.
Write(6, 3);
275 bit_writer.
Write(11, 4);
276 bit_writer.
Write(1, 5);
277 bit_writer.
Write(32, 6);
278 bit_writer.
Write(7, 7);
279 bit_writer.
Write(30497, 16);
283 uint32_t serialized_int1;
284 data >> serialized_int1;
286 uint16_t serialized_int2;
287 data >> serialized_int2;
312 const Obfuscation obfuscation{
"ffffffffffffffff"_hex};
320 const Obfuscation obfuscation{
"ff0fff0fff0fff0f"_hex};
330 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
334 for (uint8_t j = 0; j < 40; ++j) {
337 file.
seek(0, SEEK_SET);
344 }
catch (
const std::exception& e) {
346 "Rewind limit must be less than buffer size") !=
nullptr);
380 }
catch (
const std::exception& e) {
382 "Attempt to position past buffer limit") !=
nullptr);
390 for (uint8_t j = 3; j < 10; ++j) {
423 for (uint8_t j = 0; j <
sizeof(a); ++j) {
433 }
catch (
const std::exception& e) {
435 "BufferedFile::Fill: end of file") !=
nullptr);
453 BOOST_REQUIRE_EQUAL(file.
fclose(), 0);
455 fs::remove(streams_test_filename);
460 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
463 for (uint8_t j = 0; j < 40; ++j) {
466 file.
seek(0, SEEK_SET);
495 }
catch (
const std::exception& e) {
496 BOOST_CHECK(strstr(e.what(),
"Attempt to position past buffer limit") !=
nullptr);
503 BOOST_REQUIRE_EQUAL(file.
fclose(), 0);
504 fs::remove(streams_test_filename);
512 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
513 for (
int rep = 0; rep < 50; ++rep) {
515 size_t fileSize = m_rng.randrange(256);
516 for (uint8_t i = 0; i < fileSize; ++i) {
519 file.
seek(0, SEEK_SET);
521 size_t bufSize = m_rng.randrange(300) + 1;
522 size_t rewindSize = m_rng.randrange(bufSize);
524 size_t currentPos = 0;
526 for (
int step = 0; step < 100; ++step) {
527 if (currentPos >= fileSize)
538 switch (m_rng.randrange(6)) {
541 if (currentPos + 1 > fileSize)
545 for (uint8_t i = 0; i < 1; ++i) {
553 if (currentPos + 2 > fileSize)
557 for (uint8_t i = 0; i < 2; ++i) {
565 if (currentPos + 5 > fileSize)
569 for (uint8_t i = 0; i < 5; ++i) {
578 size_t skip_length{
static_cast<size_t>(m_rng.randrange(5))};
579 if (currentPos + skip_length > fileSize)
continue;
580 bf.
SetLimit(currentPos + skip_length);
581 bf.
SkipTo(currentPos + skip_length);
582 currentPos += skip_length;
587 size_t find = currentPos + m_rng.randrange(8);
588 if (find >= fileSize)
603 size_t requestPos = m_rng.randrange(maxPos + 4);
604 bool okay = bf.
SetPos(requestPos);
612 if (requestPos <= maxPos &&
613 maxPos > rewindSize &&
614 requestPos >= maxPos - rewindSize) {
621 if (maxPos < currentPos)
624 BOOST_REQUIRE_EQUAL(file.
fclose(), 0);
626 fs::remove(streams_test_filename);
631 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
632 const size_t buf_size{1 + m_rng.randrange(file_size)};
641 f.
write(m_rng.randbytes<std::byte>(file_size));
642 BOOST_REQUIRE_EQUAL(f.
fclose(), 0);
647 AutoFile direct_file{test_file.
Open(pos,
true), obfuscation};
649 AutoFile buffered_file{test_file.
Open(pos,
true), obfuscation};
650 BufferedReader buffered_reader{std::move(buffered_file), buf_size};
652 for (
size_t total_read{0}; total_read < file_size;) {
653 const size_t read{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_read))};
656 direct_file.
read(direct_file_buffer);
659 buffered_reader.
read(buffered_buffer);
662 direct_file_buffer.begin(), direct_file_buffer.end(),
663 buffered_buffer.begin(), buffered_buffer.end()
671 BOOST_CHECK_EXCEPTION(direct_file.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
676 BOOST_CHECK_EXCEPTION(buffered_reader.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
680 fs::remove(test_file.
FileName(pos));
685 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
686 const size_t buf_size{1 + m_rng.randrange(file_size)};
694 DataBuffer test_data{m_rng.randbytes<std::byte>(file_size)};
696 AutoFile direct_file{test_direct.
Open(pos,
false), obfuscation};
698 AutoFile buffered_file{test_buffered.
Open(pos,
false), obfuscation};
702 for (
size_t total_written{0}; total_written < file_size;) {
703 const size_t write_size{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_written))};
705 auto current_span = std::span{test_data}.subspan(total_written, write_size);
706 direct_file.
write(current_span);
707 buffered.
write(current_span);
709 total_written += write_size;
712 BOOST_REQUIRE_EQUAL(buffered_file.
fclose(), 0);
713 BOOST_REQUIRE_EQUAL(direct_file.
fclose(), 0);
719 AutoFile verify_direct{test_direct.
Open(pos,
true), obfuscation};
720 verify_direct.
read(direct_result);
723 BOOST_CHECK_EXCEPTION(verify_direct.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
728 AutoFile verify_buffered{test_buffered.
Open(pos,
true), obfuscation};
729 verify_buffered.
read(buffered_result);
732 BOOST_CHECK_EXCEPTION(verify_buffered.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
736 direct_result.begin(), direct_result.end(),
737 buffered_result.begin(), buffered_result.end()
740 fs::remove(test_direct.
FileName(pos));
741 fs::remove(test_buffered.
FileName(pos));
746 const uint32_t v1{m_rng.rand32()}, v2{m_rng.rand32()}, v3{m_rng.rand32()};
747 const fs::path test_file{m_args.GetDataDirBase() /
"test_buffered_write_read.bin"};
754 f.
write(std::as_bytes(std::span{&v3, 1}));
756 BOOST_REQUIRE_EQUAL(file.
fclose(), 0);
760 uint32_t _v1{0}, _v2{0}, _v3{0};
762 BufferedReader f(std::move(file),
sizeof(v1) +
sizeof(v2) +
sizeof(v3));
764 f.
read(std::as_writable_bytes(std::span{&_v3, 1}));
770 BOOST_CHECK_EXCEPTION(f.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
773 fs::remove(test_file);
780 const std::string data{
"bitcoin"};
785 hash_verifier >> result;
792 const fs::path path = m_args.GetDataDirBase() /
"size_pos_test.bin";
794 for (uint8_t j = 0; j < 10; ++j) {
821 BOOST_CHECK_EXCEPTION(f >> end, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
823 BOOST_REQUIRE_EQUAL(f.
fclose(), 0);
#define Assert(val)
Identity function.
Non-refcounted RAII wrapper for FILE*.
void ignore(size_t nSize)
void seek(int64_t offset, int origin)
Wrapper around fseek().
int64_t size()
Return the size of the file.
void write(std::span< const std::byte > src)
void read(std::span< std::byte > dst)
void Write(uint64_t data, int nbits)
Write the nbits least significant bits of a 64-bit int to the output stream.
void Flush()
Flush any unwritten bits to the output stream, padding with 0's to the next byte boundary.
Wrapper around an AutoFile& that implements a ring buffer to deserialize from.
bool eof() const
check whether we're at the end of the source file
bool SetLimit(uint64_t nPos=std::numeric_limits< uint64_t >::max())
uint64_t GetPos() const
return the current reading position
void SkipTo(const uint64_t file_pos)
void FindByte(std::byte byte)
search for a given byte in the stream, and remain positioned on it
bool SetPos(uint64_t nPos)
rewind to a given reading position
Wrapper that buffers reads from an underlying stream.
void read(std::span< std::byte > dst)
Wrapper that buffers writes to an underlying stream.
void write(std::span< const std::byte > src)
Double ended buffer combining vector and stream-like interfaces.
FlatFileSeq represents a sequence of numbered files storing raw data.
FILE * Open(const FlatFilePos &pos, bool read_only=false) const
Open a handle to the file at the given position.
fs::path FileName(const FlatFilePos &pos) const
Get the name of the file at the given position.
BOOST_CHECK_EXCEPTION predicates to check the specific validation error.
Reads data from an underlying stream, while hashing the read data.
uint256 GetHash()
Compute the double-SHA256 hash of all data written to this object.
Writes data to an underlying source stream, while hashing the written data.
std::string HexKey() const
static constexpr size_t KEY_SIZE
Minimal stream for reading from an existing byte array by std::span.
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
BOOST_AUTO_TEST_CASE(ipc_tests)
FILE * fopen(const fs::path &p, const char *mode)
static const unsigned int BLOCKFILE_CHUNK_SIZE
The pre-allocation chunk size for blk?
""_hex is a compile-time user-defined literal returning a std::array<std::byte>, equivalent to ParseH...
#define BOOST_CHECK_THROW(stmt, excMatch)
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
std::vector< std::byte > DataBuffer
BOOST_AUTO_TEST_CASE(xor_random_chunks)
@ ZEROS
Seed with a compile time constant of zeros.
BOOST_CHECK_EQUAL_COLLECTIONS(R1L.begin(), R1L.end(), R1Array, R1Array+uint256::size())