wallet_rpc_server: add weight to describe_transfer
What changed, and why it matters
This commit adds a new 'weight' field to the Monero wallet RPC command that describes a transaction. It is a routine feature enhancement: the server now reports how large (in bytes/weight units) a transaction is, which helps users estimate fees. There is no indication of a security bug being fixed.
No security action required; treat as a normal feature/API update.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch extends the wallet RPC describe_transfer response to include a ‘weight’ field. For unsigned txsets the weight is left at zero because the final transaction weight is not yet known; for signed txsets it is computed with cryptonote::get_transaction_weight. The RPC minor version is bumped and functional tests are updated to check the new field. No security-sensitive logic is changed.
Changed components
src/wallet/wallet_rpc_server.cppsrc/wallet/wallet_rpc_server_commands_defs.htests/functional_tests/cold_signing.pytests/functional_tests/multisig.pyInspect captured patch +18 / −2
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index e64df58..4f8f801 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1472,6 +1472,7 @@ namespace tools
}
std::vector <wallet2::tx_construction_data> tx_constructions;
+ std::vector<uint64_t> tx_weights;
if (!req.unsigned_txset.empty()) {
try {
tools::wallet2::unsigned_tx_set exported_txs;
@@ -1487,6 +1488,8 @@ namespace tools
return false;
}
tx_constructions = exported_txs.txes;
+ // An unsigned txset does not contain a transaction with an exact weight yet.
+ tx_weights.resize(tx_constructions.size());
}
catch (const std::exception &e) {
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
@@ -1510,6 +1513,7 @@ namespace tools
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n) {
tx_constructions.push_back(exported_txs.m_ptx[n].construction_data);
+ tx_weights.push_back(cryptonote::get_transaction_weight(exported_txs.m_ptx[n].tx));
}
}
catch (const std::exception &e) {
@@ -1532,8 +1536,9 @@ namespace tools
for (size_t n = 0; n < tx_constructions.size(); ++n)
{
const tools::wallet2::tx_construction_data &cd = tx_constructions[n];
- res.desc.push_back({0, 0, std::numeric_limits<uint32_t>::max(), 0, {}, {}, "", 0, "", 0, 0, ""});
+ res.desc.push_back({0, 0, std::numeric_limits<uint32_t>::max(), 0, {}, {}, "", 0, "", 0, 0, 0, ""});
wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::transfer_description &desc = res.desc.back();
+ desc.weight = tx_weights[n];
// Clear the recipients collection ready for this loop iteration
tx_dests.clear();
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 09d4ae9..65ed149 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 31
+#define WALLET_RPC_VERSION_MINOR 32
#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
@@ -736,6 +736,7 @@ namespace wallet_rpc
uint64_t change_amount;
std::string change_address;
uint64_t fee;
+ uint64_t weight;
uint32_t dummy_outputs;
std::string extra;
@@ -750,6 +751,7 @@ namespace wallet_rpc
KV_SERIALIZE(change_amount)
KV_SERIALIZE(change_address)
KV_SERIALIZE(fee)
+ KV_SERIALIZE_OPT(weight, (uint64_t)0)
KV_SERIALIZE(dummy_outputs)
KV_SERIALIZE(extra)
END_KV_SERIALIZE_MAP()
diff --git a/tests/functional_tests/cold_signing.py b/tests/functional_tests/cold_signing.py
index 7220a91..542cb96 100755
--- a/tests/functional_tests/cold_signing.py
+++ b/tests/functional_tests/cold_signing.py
@@ -190,6 +190,7 @@ class ColdSigningTest():
assert desc.change_amount == desc.amount_in - 1000000000000 - fee
assert desc.change_address == STANDARD_ADDRESS
assert desc.fee == fee
+ assert 'weight' not in desc
assert len(desc.recipients) == 1
rec = desc.recipients[0]
assert rec.address == destination_addr
diff --git a/tests/functional_tests/multisig.py b/tests/functional_tests/multisig.py
index a2dbfda..17c94c8 100755
--- a/tests/functional_tests/multisig.py
+++ b/tests/functional_tests/multisig.py
@@ -374,6 +374,7 @@ class MultisigTest():
amount = res.amount
assert res.fee > 0
fee = res.fee
+ weight = res.weight
assert len(res.tx_blob) == 0
assert len(res.tx_metadata) == 0
assert len(res.multisig_txset) > 0
@@ -397,6 +398,7 @@ class MultisigTest():
assert desc.change_amount == desc.amount_in - 1000000000000 - fee
assert desc.change_address == self.wallet_address
assert desc.fee == fee
+ assert desc.weight == weight
assert len(desc.recipients) == 1
rec = desc.recipients[0]
assert rec.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
@@ -413,6 +415,10 @@ class MultisigTest():
except: ok = True
assert ok
+ res = self.wallet[signers[-1]].describe_transfer(multisig_txset = multisig_txset)
+ assert len(res.desc) == 1
+ assert res.desc[0].weight == weight
+
print('Submitting multisig transaction with wallet ' + str(signers[-1]))
res = self.wallet[signers[-1]].submit_multisig(multisig_txset)
assert len(res.tx_hash_list) == 1
@@ -470,6 +476,7 @@ class MultisigTest():
amount = res.amount
assert res.fee > 0
fee = res.fee
+ weight = res.weight
assert len(res.tx_blob) == 0
assert len(res.tx_metadata) == 0
assert len(res.multisig_txset) > 0
@@ -522,6 +529,7 @@ class MultisigTest():
assert desc.change_amount == desc.amount_in - 1000000000000 - fee
assert desc.change_address == self.wallet_address
assert desc.fee == fee
+ assert desc.weight == weight
assert len(desc.recipients) == 1
rec = desc.recipients[0]
assert rec.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
Why this scored 19/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.