There are currently three different ways to do this: raw transactions, PSBT in 0.17, and PSBT in 0.18. I recommend that you use PSBT in 0.18 as it is the least hassle, but I will describe all three here for you.
Traditionally, you would do this with
signrawtransactionwithwallet. One person would have to know all of the inputs that were being used in the transaction or have all of those stored in their wallet (i.e. they have imported everyone else's public keys and/or redeemScripts into their wallet) and then they can use
fundrawtransaction to create the raw transaction.
createrawtransaction just takes inputs and outputs that are specified by the user and gives the resulting transaction as is (so you need to be careful about fees and change).
fundrawtransaction can choose the inputs to use for you using your wallet and it will handle fees and change outputs itself. However
fundrawtransaction needs to know all of the information necessary to construct the final transaction (except for the private key, it can just use a dummy signature) in order to correctly estimate the transaction fees, which is why you need to import the public keys and scripts into your wallet.
Once you have the raw transaction, you then send it to each of the other people involved in the transaction. They then sign it using
signrawtransactionwithwallet (if the keys and scripts are in their wallet) or
signrawtransactionwithkey (if their keys and scripts are not in their wallet). Most people will use
signrawtransactionwithwallet. They then send the result back to you where you have to combine all of the signed transactions into the final transaction using
combinerawtransaction. Then you can broadcast it with
Instead of sending the transactions out to everyone to sign at the same time, you could send to one person who signs, who then sends to the next person and so on. This would not require
combinerawtransaction. The last person would sign and then use
sendrawtransaction to broadcast.
This process is kind of bulky and requires that one person knows some (or all) of the information for the inputs being used (except for the private keys).
Since Bitcoin Core 0.17, you can use the various
*psbt RPCs to achieve the same thing. With 0.17, the flow is fairly similar to the the raw transaction flow described earlier. You would have to have all of the information for creating the final transaction in your wallet (except for private keys) so that fee estimation can be properly done for coin selection, or you need to know which inputs to use. Either way, you use
walletcreatefundedpsbt and specify the inputs you want and the outputs you want. Bitcoin Core will then automatically choose additional inputs if there is not enough to cover the output amount and create a change output for you. Because it needs to also conver transaction fees, it needs to have the same information that you need for
fundrawtransaction to be able to estimate fees for the inputs it chooses.
Then you would send the transaction to everyone else who would add their signatures (and other metadata) using
walletprocesspsbt. You can also do
walletprocesspsbt first before sending the transaction to everyone so that various metadata needed for signing (like the UTXO that is being spent for each input) is added beforehand. Once signed, everyone would send the transaction back to you and you combine them together using
combinepsbts Then you create the final transaction for broadcast using
finalizepsbt and send the result using
Of course using PSBTs you can do the same thing described above where each person sends the transaction to the next person to be signed instead of sending back to you to be combined.
Again, this process is kind of bulky and requires that one person knows some (or all) of information for the inputs being used (except for the private keys). But it is slightly less likely to result in an error than the raw transaction method. PSBTs also allows you to use other non-Bitcoin Core wallets that support PSBT, and you can use this method with wallets which are not connected to the internet or otherwise do not have the blockchain or the UTXOs that are being spent in the transaction.
However, Bitcoin Core 0.18 actually makes this whole process a lot easier. Bitcoin Core 0.18 introduces a couple of new
*psbt RPCs which make it so that one person does not need to know all of the inputs being used and all of the information for each input. The only caveat is that this method assumes that each person has their own outputs that they want to create instead of multiple people pooling together their Bitcoin to make one large output.
With 0.18, everyone would create their own PSBT using
walletcreatefundedpsbt. They specify any of their own inputs that they want to use and all of their outputs. Any change outputs will be added, and additional inputs from the wallet will be added to cover the output amount and transaction fee if not enough were specified by the user. Since every user does this with their own wallet, no one person needs to know anything about what the other users have in their wallets.
Then each person would send the PSBT to a designated coordinator who uses
joinpsbts to join every PSBT into one large PSBT. This PSBT will have all of the inputs and outputs that each person wants to spend and create. So instead of having many individual PSBTs with their own inputs and outputs, there is now one large PSBT with everyone's inputs and outputs.
This PSBT is then sent back to each person who uses
walletprocesspsbt to update the PSBT and add their input information to the PSBT and signs it. Even if a user has an airgapped setup where their private keys are somewhere that does not have access to the blockchain, they can update the PSBT from an online watching only wallet and send the PSBT to the offline machine to be signed.
Once everyone has signed the PSBT, it is sent back to the coordinator who uses
combinepsbt to combine all of the signatures and input information into the same PSBT, then creates the final network transaction using
finalizepsbt and broadcasts it using
Again, this can be done serially like the other methods described earlier and thus omit the need for