Port monero-lws to wownero-lws

Adapts monero-lws for Wownero cryptocurrency:

- Rename all monero-lws-* binaries to wownero-lws-*
- Update submodule to point to official Wownero repo
- Use Wownero default ports (RPC: 34568, ZMQ: 34569)
- Update data directory to ~/.wownero/light_wallet_server
- Adapt next_difficulty() calls for Wownero API signature

Key technical changes for Wownero compatibility:

- BulletproofPlus (RCTTypeBulletproofPlus, type 8) commitment verification:
  Wownero stores BP+ commitments in 'divided by 8' form. Must call
  rct::scalarmult8() on outPk commitment before comparing with computed
  commitment (mask*G + amount*H). This is essential for amount decryption.

- Pass rct_type to decode_amount() for proper commitment handling

- Handle Wownero's ZMQ JSON format for ecdhTuple (32-byte mask/amount fields)

No fork of Wownero is required - uses official codeberg.org/wownero/wownero.
This commit is contained in:
jwinterm
2026-01-04 13:12:56 -05:00
parent f2b3534002
commit 97877eda27
35 changed files with 809 additions and 396 deletions

View File

@@ -1,4 +1,5 @@
# Copyright (c) 2020-2024, The Monero Project
# Copyright (c) 2024-2025, The Wownero Project
#
# All rights reserved.
#
@@ -28,9 +29,9 @@
add_subdirectory(scanner)
set(monero-lws-rpc_sources admin.cpp client.cpp daemon_pub.cpp daemon_zmq.cpp light_wallet.cpp lws_pub.cpp rates.cpp)
set(monero-lws-rpc_headers admin.h client.h daemon_pub.h daemon_zmq.h fwd.h json.h light_wallet.h lws_pub.h rates.h)
set(wownero-lws-rpc_sources admin.cpp client.cpp daemon_pub.cpp daemon_zmq.cpp light_wallet.cpp lws_pub.cpp rates.cpp)
set(wownero-lws-rpc_headers admin.h client.h daemon_pub.h daemon_zmq.h fwd.h json.h light_wallet.h lws_pub.h rates.h)
add_library(monero-lws-rpc ${monero-lws-rpc_sources} ${monero-lws-rpc_headers})
target_include_directories(monero-lws-rpc PRIVATE ${RMQ_INCLUDE_DIR})
target_link_libraries(monero-lws-rpc monero::libraries monero-lws-util monero-lws-wire-json monero-lws-wire-wrapper ${RMQ_LIBRARY})
add_library(wownero-lws-rpc ${wownero-lws-rpc_sources} ${wownero-lws-rpc_headers})
target_include_directories(wownero-lws-rpc PRIVATE ${RMQ_INCLUDE_DIR})
target_link_libraries(wownero-lws-rpc wownero::libraries wownero-lws-util wownero-lws-wire-json wownero-lws-wire-wrapper ${RMQ_LIBRARY})

View File

@@ -71,7 +71,7 @@ namespace rpc
constexpr const char abort_process_signal[] = "PROCESS";
constexpr const char minimal_chain_topic[] = "json-minimal-chain_main";
constexpr const char full_txpool_topic[] = "json-full-txpool_add";
constexpr const int daemon_zmq_linger = 0;
constexpr const int daemon_zmq_linger = 1000;
constexpr const int account_zmq_linger = 0;
constexpr const std::int64_t max_msg_sub = 10 * 1024 * 1024; // 50 MiB
constexpr const std::int64_t max_msg_req = 350 * 1024 * 1024; // 350 MiB

View File

@@ -28,9 +28,12 @@
#include "daemon_zmq.h"
#include <boost/optional/optional.hpp>
#include "misc_log_ex.h"
#include "string_tools.h"
#include "cryptonote_config.h" // monero/src
#include "crypto/crypto.h" // monero/src
#include "rpc/message_data_structs.h" // monero/src
#include "ringct/rctOps.h"
#include "wire/adapted/crypto.h"
#include "wire/json.h"
#include "wire/wrapper/array.h"
@@ -61,15 +64,23 @@ namespace
namespace rct
{
static void read_bytes(wire::json_reader& source, key& self)
{
source.binary(epee::as_mut_byte_span(self.bytes));
}
static void read_bytes(wire::json_reader& source, ctkey& self)
{
self.dest = {};
read_bytes(source, self.mask);
source.binary(epee::as_mut_byte_span(self.mask));
}
static void read_bytes(wire::json_reader& source, ecdhTuple& self)
{
wire::object(source, WIRE_FIELD(mask), WIRE_FIELD(amount));
wire::object(source,
WIRE_FIELD(mask),
WIRE_FIELD(amount)
);
}
static void read_bytes(wire::json_reader& source, clsag& self)
@@ -205,6 +216,11 @@ namespace rct
wire::optional_field("prunable", std::ref(prunable))
);
if (self.type != RCTTypeNull)
{
MDEBUG("Parsed rctSig: type=" << (int)self.type << " encrypted_count=" << self.ecdhInfo.size() << " commitments_count=" << self.outPk.size());
}
self.txnFee = 0;
if (self.type != RCTTypeNull)
{
@@ -213,7 +229,7 @@ namespace rct
self.txnFee = std::move(*txnFee);
}
else if (!self.ecdhInfo.empty() || !self.outPk.empty() || txnFee)
WIRE_DLOG_THROW(wire::error::schema::invalid_key, "Did not expected `encrypted`, `commitments`, or `fee`");
WIRE_DLOG_THROW(wire::error::schema::invalid_key, "Did not expect `encrypted`, `commitments`, or `fee`");
if (prunable)
{
@@ -289,30 +305,47 @@ namespace cryptonote
self.vin.reserve(default_inputs);
self.vout.reserve(default_outputs);
self.extra.reserve(default_txextra_size);
boost::optional<rct::rctSig> ringct;
wire::object(source,
WIRE_FIELD(version),
WIRE_FIELD(unlock_time),
wire::field("inputs", wire::array<max_inputs_per_tx>(std::ref(self.vin))),
wire::field("outputs", wire::array<max_outputs_per_tx>(std::ref(self.vout))),
WIRE_FIELD(extra),
WIRE_FIELD_ARRAY(signatures, max_inputs_per_tx),
wire::field("ringct", std::ref(self.rct_signatures))
wire::optional_field("signatures", wire::array<max_inputs_per_tx>(std::ref(self.signatures))),
wire::optional_field("ringct", std::ref(ringct))
);
if (ringct)
self.rct_signatures = std::move(*ringct);
}
static void read_bytes(wire::json_reader& source, block& self)
{
using min_hash_size = wire::min_element_sizeof<crypto::hash>;
self.tx_hashes.reserve(default_transaction_count);
boost::optional<crypto::signature> signature;
boost::optional<uint16_t> vote;
wire::object(source,
WIRE_FIELD(major_version),
WIRE_FIELD(minor_version),
WIRE_FIELD(timestamp),
WIRE_FIELD(miner_tx),
WIRE_FIELD_ARRAY(tx_hashes, min_hash_size),
WIRE_FIELD(prev_id),
WIRE_FIELD(nonce)
WIRE_FIELD(nonce),
wire::optional_field("signature", std::ref(signature)),
wire::optional_field("vote", std::ref(vote)),
WIRE_FIELD(miner_tx),
WIRE_FIELD_ARRAY(tx_hashes, min_hash_size)
);
if (signature)
self.signature = *signature;
if (vote)
self.vote = *vote;
}
static void read_bytes(wire::json_reader& source, std::vector<transaction>& self)

View File

@@ -1,4 +1,5 @@
# Copyright (c) 2024, The Monero Project
# Copyright (c) 2024-2025, The Wownero Project
#
# All rights reserved.
#
@@ -26,12 +27,12 @@
# 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.
set(monero-lws-rpc-scanner_sources
set(wownero-lws-rpc-scanner_sources
client.cpp commands.cpp connection.cpp queue.cpp server.cpp write_commands.cpp
)
set(monero-lws-rpc-scanner_headers
set(wownero-lws-rpc-scanner_headers
client.h commands.h connection.h fwd.h queue.h read_commands.h server.h write_commands.h
)
add_library(monero-lws-rpc-scanner ${monero-lws-rpc-scanner_sources} ${monero-lws-rpc-scanner_headers})
target_link_libraries(monero-lws-rpc-scanner monero::libraries monero-lws-wire-msgpack)
add_library(wownero-lws-rpc-scanner ${wownero-lws-rpc-scanner_sources} ${wownero-lws-rpc-scanner_headers})
target_link_libraries(wownero-lws-rpc-scanner wownero::libraries wownero-lws-wire-msgpack)