Fix/claude report (#11)

* Fix send_tx status check

* Store feed websocket shared_ptr in-strand

* Check mixin/decoy size from server

* Harden/limit listener block notifications

* Fix new ascii unit test

* Fix CMake changes from upstream

(cherry picked from commit 19cb285dab6c1962a38865a7966f823925c030bd)
This commit is contained in:
Lee *!* Clagett
2026-10-05 20:46:55 -04:00
committed by such-gitea
parent 52e45623e8
commit 0054b0b06a
11 changed files with 207 additions and 9 deletions
+13 -5
View File
@@ -54,6 +54,15 @@ cmake_path(CONVERT "${MONERO_SOURCE_DIR}" TO_CMAKE_PATH_LIST MONERO_SOURCE_DIR_C
include(FetchContent)
FetchContent_Declare(monero SOURCE_DIR ${MONERO_SOURCE_DIR_CONVERTED} EXCLUDE_FROM_ALL)
if (NOT LWSF_MASTER_ENABLE)
set(Boost_NO_BOOST_CMAKE ON)
endif ()
if(STATIC)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
endif()
if (NOT monero_POPULATED)
FetchContent_MakeAvailable(monero)
endif ()
@@ -65,12 +74,11 @@ endif ()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(Boost_NO_BOOST_CMAKE ON)
if(STATIC)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
endif()
if (LWSF_MASTER_ENABLE)
find_package(Boost 1.66 QUIET REQUIRED COMPONENTS filesystem program_options thread CONFIG)
else ()
find_package(Boost 1.66 QUIET REQUIRED COMPONENTS filesystem program_options thread)
endif()
list(INSERT CMAKE_MODULE_PATH 0
"${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+2
View File
@@ -41,6 +41,7 @@ set(lwsf_sources
subaddress_minor.cpp
transaction_history.cpp
transaction_info.cpp
utils/ascii.cpp
utils/encrypted_file.cpp
wallet.cpp
wallet_manager.cpp
@@ -53,6 +54,7 @@ set(lwsf_headers
pending_transaction.h
transaction_history.h
transaction_info.h
utils/ascii.h
utils/encrypted_file.h
utils/numeric.h
wallet.h
+20 -3
View File
@@ -43,6 +43,7 @@
#include "lwsf_config.h"
#include "net/websocket.h"
#include "ringct/rctOps.h"
#include "utils/ascii.h"
#include "wire.h"
#include "wire/adapted/crypto.h"
#include "wire/adapted/pair.h"
@@ -715,8 +716,19 @@ namespace lwsf { namespace internal { namespace backend
if (!merged.new_transactions.empty() || new_height - orig_height)
listener.updated();
for (std::uint64_t i = orig_height; i < new_height; ++i)
// Call `listener.newBlock` a max of `config::notify_block_limit` times
const std::uint64_t diff = new_height - orig_height;
const std::uint64_t shift =
std::max(diff / config::notify_block_limit, std::uint64_t(1));
for (std::uint64_t i = orig_height; i < new_height; i += shift)
{
listener.newBlock(i);
if (std::numeric_limits<std::uint64_t>::max() - shift < i)
break;
}
if (diff && diff % shift != 0)
listener.newBlock(new_height - 1);
for (const auto& tx : merged.new_transactions)
{
@@ -1827,7 +1839,7 @@ namespace lwsf { namespace internal { namespace backend
{
ws_connect:
BOOST_ASIO_CORO_YIELD self.client.ws_async(
rpc::feed::endpoint(), rpc::feed::protocol(), store(&self.feed, wrap(self_ptr, *this))
rpc::feed::endpoint(), rpc::feed::protocol(), wrap(self_ptr, store(&self.feed, wrap(self_ptr, *this)))
);
if (!error && self.feed)
@@ -1867,7 +1879,7 @@ namespace lwsf { namespace internal { namespace backend
}
}
frame_->orig_scan_height = self.primary.scan_height;
frame_->orig_scan_height = std::max(self.primary.scan_height, self.primary.restore_height);
frame_->login = rpc::login{self.primary.address, self.primary.view.sec};
BOOST_ASIO_CORO_YIELD rpc::invoke_async(
self.client, frame_->login, std::addressof(frame_->txs_response), wrap(self_ptr, *this)
@@ -2399,7 +2411,12 @@ namespace lwsf { namespace internal { namespace backend
std::addressof(frame_->response),
*this
);
if (error)
frame_->f(error);
else if (!ascii_nocase_compare(frame_->response.status, "OK"))
frame_->f(error::send_not_ok);
else
frame_->f({});
}
}
};
+2
View File
@@ -60,6 +60,8 @@ namespace lwsf
return "Import/restore from height is awaiting approval";
case error::network_type:
return "Mismatch on network type";
case error::send_not_ok:
return "send_tx status was NOT ok";
case error::subaddr_ahead:
return "server has limits too low for requested subaddress lookahead";
case error::subaddr_disabled:
+1
View File
@@ -54,6 +54,7 @@ namespace lwsf
import_pending, //!< `import_wallet_request` not fulfilled/approved
invalid_scheme, //!< Invalid network scheme
network_type, //!< Mismatch on network type
send_not_ok, //!< `send_tx` status was NOT `OK`.
subaddr_ahead, //!< Server limits on subaddresses affects lookahead
subaddr_disabled, //!< Server has subaddresses disabled
subaddr_local, //!< Local limits on subaddresses too small
+1
View File
@@ -59,6 +59,7 @@ namespace lwsf { namespace config
constexpr const std::size_t max_txes_in_rpc = 2048;
constexpr const std::size_t min_outputs = 2;
constexpr const std::uint32_t mixin_default = 21; // Wownero ring size 22 (mixin + 1)
constexpr const unsigned notify_block_limit = 1024; // max block notifications (via listener) in one shot
constexpr const std::chrono::seconds ping_timeout{10};
constexpr const std::chrono::seconds refresh_interval{30};
constexpr const std::chrono::seconds refresh_interval_min{5};
+54
View File
@@ -0,0 +1,54 @@
// Copyright (c) 2025, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ascii.h"
namespace lwsf { namespace internal
{
namespace
{
char to_low_case(char in) noexcept
{
if (u8'A' <= in && in <= u8'Z')
return in ^ 0x20;
return in;
}
}
bool ascii_nocase_compare(const std::string_view left, const std::string_view right)
{
if (left.size() != right.size())
return false;
for (std::size_t i = 0; i < left.size(); ++i)
{
if (to_low_case(left[i]) != to_low_case(right[i]))
return false;
}
return true;
}
}} // lwsf // internal
+36
View File
@@ -0,0 +1,36 @@
// Copyright (c) 2025, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <string_view>
namespace lwsf { namespace internal
{
bool ascii_nocase_compare(std::string_view left, std::string_view right);
}} // lwsf // internal
+2
View File
@@ -1595,6 +1595,8 @@ namespace lwsf { namespace internal
const auto ring = std::lower_bound(decoys.begin(), decoys.end(), amount, by_amount{});
if (ring == decoys.end() || ring->amount != rpc::uint64_string(amount))
throw std::runtime_error{"Missing requested decoys"};
if (ring->outputs.size() != mixin_count)
throw std::runtime_error{"Unexpected decoy (mixin) count from server"};
for (const auto& decoy : ring->outputs)
entry.outputs.emplace_back(std::uint64_t(decoy.global_index), rct::ctkey{decoy.public_key, decoy.rct});
+30
View File
@@ -0,0 +1,30 @@
# Copyright (c) 2025, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_library(lwsf-unit-util OBJECT ascii.test.cpp)
target_link_libraries(lwsf-unit-util PRIVATE lwsf-unit-framework lwsf)
+45
View File
@@ -0,0 +1,45 @@
// Copyright (c) 2025, The Monero Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "framework.test.h"
#include "util/ascii.h"
LWS_CASE("util::ascii")
{
EXPECT(lwsf::internal::ascii_nocase_compare("OK", "ok"));
EXPECT(lwsf::internal::ascii_nocase_compare("OK", "oK"));
EXPECT(lwsf::internal::ascii_nocase_compare("OK", "OK"));
EXPECT(lwsf::internal::ascii_nocase_compare("Ok", "OK"));
EXPECT(lwsf::internal::ascii_nocase_compare("oK", "OK"));
EXPECT(lwsf::internal::ascii_nocase_compare("ok", "OK"));
EXPECT(lwsf::internal::ascii_nocase_compare("ok", "Ok"));
EXPECT(lwsf::internal::ascii_nocase_compare("ok", "oK"));
EXPECT(lwsf::internal::ascii_nocase_compare("ok", "ok"));
EXPECT(lwsf::internal::ascii_nocase_compare("-->", "-->"));
EXPECT(!lwsf::internal::ascii_nocase_compare("Double spend", "OK"));
}