wallet_rpc_server: leave unknown incoming tx hash empty
What changed, and why it matters
This Monero wallet RPC patch changes how transaction hashes are reported for incoming transfers that the wallet does not know the source transaction for. Previously, the RPC would return a string of all-zero characters ('0000...0000') as the transaction hash. After the patch, it returns an empty string instead. This is a correctness and API-clarity fix rather than a direct exploit, but returning a fake all-zero hash could have misled downstream software into treating an unknown transfer as a known one.
Treat as a low-severity correctness fix. Downstream RPC consumers should review handling of empty tx_hash fields in incoming_transfer responses and ensure they do not rely on the previous all-zero placeholder. No urgent patching is required, but including the fix in the next release is prudent.
Security signals we found
Behavioral change in RPC output for unknown transaction hashes
Previously returned crypto::null_hash hex string could be mistaken for a valid txid by consumers
Version bump indicates API-visible change
Functional test explicitly checks that cold/unknown transfers now produce empty tx_hash
Evidence from the diff
In wallet_rpc_server.cpp, the code building RPC transfer entries now checks whether td.m_txid equals crypto::null_hash. If so, it sets rpc_transfers.tx_hash to an empty string; otherwise it hex-encodes the real txid. The wallet RPC minor version is bumped from 32 to 33, signaling a client-visible behavioral change. A functional test in cold_signing.py is updated to assert that hot-wallet transfers still have a valid 64-character non-zero tx_hash, while cold-wallet transfers have an empty tx_hash. The change affects only the representation of unknown incoming transfers in RPC responses.
Changed components
src/wallet/wallet_rpc_server.cppsrc/wallet/wallet_rpc_server_commands_defs.htests/functional_tests/cold_signing.pyInspect captured patch +5 / −2
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 6395b6c..e8f49a3 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -2269,7 +2269,7 @@ namespace tools
rpc_transfers.amount = td.amount();
rpc_transfers.spent = td.m_spent;
rpc_transfers.global_index = td.m_global_output_index;
- rpc_transfers.tx_hash = epee::string_tools::pod_to_hex(td.m_txid);
+ rpc_transfers.tx_hash = td.m_txid == crypto::null_hash ? "" : epee::string_tools::pod_to_hex(td.m_txid);
rpc_transfers.subaddr_index = {td.m_subaddr_index.major, td.m_subaddr_index.minor};
rpc_transfers.key_image = td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : "";
rpc_transfers.pubkey = epee::string_tools::pod_to_hex(td.get_public_key());
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index ebd55da..8a80dc2 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 32
+#define WALLET_RPC_VERSION_MINOR 33
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
diff --git a/tests/functional_tests/cold_signing.py b/tests/functional_tests/cold_signing.py
index 542cb96..09adbeb 100755
--- a/tests/functional_tests/cold_signing.py
+++ b/tests/functional_tests/cold_signing.py
@@ -145,6 +145,9 @@ class ColdSigningTest():
if do_check_key_images:
attributes_to_cmp.append("key_image")
for i in range(len(hot_transfers_list)):
+ assert len(hot_transfers_list[i]['tx_hash']) == 64
+ assert hot_transfers_list[i]['tx_hash'] != '0' * 64
+ assert cold_transfers_list[i]['tx_hash'] == '', cold_transfers_list[i]['tx_hash']
for attr in attributes_to_cmp:
hot_val = hot_transfers_list[i][attr]
cold_val = cold_transfers_list[i][attr]
Why this scored 25/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.