Merge #16512: rpc: Shuffle inputs and outputs after joining psbts
c0b5d9710322a614a50ab5da081558cf6a38ad2a Test that joinpsbts randomly shuffles the inputs (Andrew Chow)
6f405a1d3b38395e35571b68aae55cae50e0762a Shuffle inputs and outputs after joining psbts (Andrew Chow)
Pull request description:
`joinpsbts` currently just adds the inputs and outputs in the order of that the PSBTs were provided. This makes it extremely easy to identify which outputs belong to which inputs. This PR changes that so that all of the inputs and outputs are shuffled in the joined transaction.
ACKs for top commit:
instagibbs:
utACK c0b5d97103
jonatack:
ACK c0b5d9710322a614a50ab5da081558cf6a38ad2a modulo suggestions for later.
Tree-SHA512: 14a0b7aae07d92e6d2c76a3a3b228b481e1964cb7d34f97515bdda18e2ea05a9f97c5a22affc143b86ae8b95c3cb239849fb54219d65512bc2112264dca915c8
This commit is contained in:
commit
72d30d668a
4
doc/release-notes-16512.md
Normal file
4
doc/release-notes-16512.md
Normal file
@ -0,0 +1,4 @@
|
||||
RPC changes
|
||||
-----------
|
||||
The RPC `joinpsbts` will shuffle the order of the inputs and outputs of the resulting joined psbt.
|
||||
Previously inputs and outputs were added in the order that the PSBTs were provided which makes correlating inputs to outputs extremely easy.
|
||||
@ -17,6 +17,7 @@
|
||||
#include <policy/rbf.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <psbt.h>
|
||||
#include <random.h>
|
||||
#include <rpc/rawtransaction_util.h>
|
||||
#include <rpc/server.h>
|
||||
#include <rpc/util.h>
|
||||
@ -1615,8 +1616,30 @@ UniValue joinpsbts(const JSONRPCRequest& request)
|
||||
merged_psbt.unknown.insert(psbt.unknown.begin(), psbt.unknown.end());
|
||||
}
|
||||
|
||||
// Generate list of shuffled indices for shuffling inputs and outputs of the merged PSBT
|
||||
std::vector<int> input_indices(merged_psbt.inputs.size());
|
||||
std::iota(input_indices.begin(), input_indices.end(), 0);
|
||||
std::vector<int> output_indices(merged_psbt.outputs.size());
|
||||
std::iota(output_indices.begin(), output_indices.end(), 0);
|
||||
|
||||
// Shuffle input and output indicies lists
|
||||
Shuffle(input_indices.begin(), input_indices.end(), FastRandomContext());
|
||||
Shuffle(output_indices.begin(), output_indices.end(), FastRandomContext());
|
||||
|
||||
PartiallySignedTransaction shuffled_psbt;
|
||||
shuffled_psbt.tx = CMutableTransaction();
|
||||
shuffled_psbt.tx->nVersion = merged_psbt.tx->nVersion;
|
||||
shuffled_psbt.tx->nLockTime = merged_psbt.tx->nLockTime;
|
||||
for (int i : input_indices) {
|
||||
shuffled_psbt.AddInput(merged_psbt.tx->vin[i], merged_psbt.inputs[i]);
|
||||
}
|
||||
for (int i : output_indices) {
|
||||
shuffled_psbt.AddOutput(merged_psbt.tx->vout[i], merged_psbt.outputs[i]);
|
||||
}
|
||||
shuffled_psbt.unknown.insert(merged_psbt.unknown.begin(), merged_psbt.unknown.end());
|
||||
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssTx << merged_psbt;
|
||||
ssTx << shuffled_psbt;
|
||||
return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
|
||||
}
|
||||
|
||||
|
||||
@ -382,6 +382,16 @@ class PSBTTest(BitcoinTestFramework):
|
||||
joined_decoded = self.nodes[0].decodepsbt(joined)
|
||||
assert len(joined_decoded['inputs']) == 4 and len(joined_decoded['outputs']) == 2 and "final_scriptwitness" not in joined_decoded['inputs'][3] and "final_scriptSig" not in joined_decoded['inputs'][3]
|
||||
|
||||
# Check that joining shuffles the inputs and outputs
|
||||
# 10 attempts should be enough to get a shuffled join
|
||||
shuffled = False
|
||||
for i in range(0, 10):
|
||||
shuffled_joined = self.nodes[0].joinpsbts([psbt, psbt2])
|
||||
shuffled |= joined != shuffled_joined
|
||||
if shuffled:
|
||||
break
|
||||
assert shuffled
|
||||
|
||||
# Newly created PSBT needs UTXOs and updating
|
||||
addr = self.nodes[1].getnewaddress("", "p2sh-segwit")
|
||||
txid = self.nodes[0].sendtoaddress(addr, 7)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user