test: aggregate send destinations by address instead of order
What changed, and why it matters
This commit only changes a test file. It updates how a Monero wallet test checks transaction destinations: instead of comparing each destination in the exact order it was sent, it now adds up the amounts sent to each address and compares the totals. This is a test-only adjustment to match how the upstream Monero software actually behaves, not a fix for a security problem in production code.
No security action needed. This is a test-only refactor improving test robustness against upstream Monero transaction construction behavior.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff modifies TestMoneroWalletCommon.java’s testTxsWallet helper. Previously the test iterated ctx.config.getDestinations() positionally and asserted each tx destination matched the corresponding config entry. Because monero-project can reorder or split destinations, the test is changed to aggregate expected and actual amounts per address using HashMap.merge(…, BigInteger::add). For fee-subtraction cases it now checks that the sum of (expected - actual) across all addresses equals the sum of fees, rather than per-destination differences. No library/runtime code is changed.
Changed components
src/test/java/TestMoneroWalletCommon.javaInspect captured patch +17 / −10
diff --git a/src/test/java/TestMoneroWalletCommon.java b/src/test/java/TestMoneroWalletCommon.java
index e96b2b2..b55421f 100644
--- a/src/test/java/TestMoneroWalletCommon.java
+++ b/src/test/java/TestMoneroWalletCommon.java
@@ -5543,10 +5543,13 @@ public abstract class TestMoneroWalletCommon {
assertTrue(txs.size() > 0);
for (MoneroTxWallet tx : txs) testTxWallet(tx, ctx);
- // test destinations across transactions
+ // test destinations across transactions; monero-project does not preserve destination order or splitting, so aggregate by address
if (ctx.config != null && ctx.config.getDestinations() != null) {
- int destinationIdx = 0;
boolean subtractFeeFromDestinations = ctx.config.getSubtractFeeFrom() != null && ctx.config.getSubtractFeeFrom().size() > 0;
+ Map<String, BigInteger> expectedAmounts = new HashMap<String, BigInteger>();
+ for (MoneroDestination destination : ctx.config.getDestinations()) expectedAmounts.merge(destination.getAddress(), destination.getAmount(), BigInteger::add);
+ Map<String, BigInteger> actualAmounts = new HashMap<String, BigInteger>();
+ BigInteger feeSum = BigInteger.valueOf(0);
for (MoneroTxWallet tx : txs) {
// TODO: remove this after >18.3.1 when amounts_by_dest_list is official
@@ -5555,17 +5558,21 @@ public abstract class TestMoneroWalletCommon {
return;
}
- BigInteger amountDiff = BigInteger.valueOf(0);
+ feeSum = feeSum.add(tx.getFee());
for (MoneroDestination destination : tx.getOutgoingTransfer().getDestinations()) {
- MoneroDestination ctxDestination = ctx.config.getDestinations().get(destinationIdx);
- assertEquals(ctxDestination.getAddress(), destination.getAddress());
- if (subtractFeeFromDestinations) amountDiff = amountDiff.add(ctxDestination.getAmount().subtract(destination.getAmount()));
- else assertEquals(ctxDestination.getAmount(), destination.getAmount());
- destinationIdx++;
+ assertTrue(expectedAmounts.containsKey(destination.getAddress()), "Destination address not in config");
+ actualAmounts.merge(destination.getAddress(), destination.getAmount(), BigInteger::add);
}
- if (subtractFeeFromDestinations) assertEquals(amountDiff, tx.getFee());
}
- assertEquals(destinationIdx, ctx.config.getDestinations().size());
+
+ // each destination receives its requested amount, less fee if subtracted from destinations
+ if (subtractFeeFromDestinations) {
+ BigInteger amountDiff = BigInteger.valueOf(0);
+ for (String address : expectedAmounts.keySet()) amountDiff = amountDiff.add(expectedAmounts.get(address).subtract(actualAmounts.getOrDefault(address, BigInteger.valueOf(0))));
+ assertEquals(feeSum, amountDiff);
+ } else {
+ assertEquals(expectedAmounts, actualAmounts);
+ }
}
}
Why this scored 15/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.