This works! Following the hint from #29415 (review) I could integrate it into the tests of #29415 to try to send two transactions that have the same txid and different wtxid.
However using it is a bit involved - one has to create a new dedicated parent transaction, get it in the mempool and then broadcast the two children. Also, one has to handle the fees manually. Like this:
0self.log.info("Sending a pair of transactions with same txid and different and valid wtxid via RPC")
1txgen = ValidWitnessMalleatedTx()
2funding = wallet.get_utxo()
3fee_sat = 1000
4siblings_parent = txgen.build_parent_tx(funding["txid"], amount=funding["value"] * COIN - fee_sat)
5sibling1, sibling2 = txgen.build_malleated_children(siblings_parent.txid_hex, amount=siblings_parent.vout[0].nValue - fee_sat)
6self.log.info(f" - sibling1: txid={sibling1.txid_hex}, wtxid={sibling1.wtxid_hex}")
7self.log.info(f" - sibling2: txid={sibling2.txid_hex}, wtxid={sibling2.wtxid_hex}")
8wallet.sign_tx(siblings_parent)
9tx_returner.send_without_ping(msg_tx(siblings_parent))
10self.wait_until(lambda: len(tx_originator.getrawmempool()) > 1)
11self.log.info(" - siblings' parent added to the mempool")
12assert_equal(sibling1.txid_hex, sibling2.txid_hex)
13assert_not_equal(sibling1.wtxid_hex, sibling2.wtxid_hex)
14tx_originator.sendrawtransaction(hexstring=sibling1.serialize_with_witness().hex(), maxfeerate=0.1)
15self.log.info(f" - sent sibling1: ok")
16ignoring_msg = f"Ignoring unnecessary request to schedule an already scheduled transaction: txid={sibling2.txid_hex}, wtxid={sibling2.wtxid_hex}"
17with tx_originator.busy_wait_for_debug_log(expected_msgs=[ignoring_msg.encode()]):
18 tx_originator.sendrawtransaction(hexstring=sibling2.serialize_with_witness().hex(), maxfeerate=0.1)
19self.log.info(f" - sibling2 rejected because it has the same txid: ok")
Given that the test already has a transaction that has been sent, I imagined it could be simpler:
0self.log.info("Sending a malleated transaction with a valid witness via RPC")
1malleated_valid = malleate_tx(txs[0], valid_witness=True)
2ignoring_msg = f"Ignoring unnecessary request to schedule an already scheduled transaction: txid={malleated_valid.txid_hex}, wtxid={malleated_valid.wtxid_hex}"
3with tx_originator.busy_wait_for_debug_log(expected_msgs=[ignoring_msg.encode()]):
4 tx_originator.sendrawtransaction(hexstring=malleated_valid.serialize_with_witness().hex(), maxfeerate=0.1)