Let's diagram an example hard fork block chain:
A <-- B <-- C <-- D (current consensus rules chain, "original chain")
^---- C' <-- D' (new consensus rules chain, "new chain")
If you received a transaction output in block A or B, you could spend it on both the original chain and the new chain[*]. How that would work out depends a lot of whether the new chain includes replay protection.
Replay protection
The new chain may optionally require replay protection, which would most likely be a change in the data used to create the transaction signature. For example, normally a transaction signature signs a hash of the identifier of the inputs being spent as well as all of the outputs; for a hard fork, this could be changed to require the signature hash additionally include the value "Hard Fork #123". This would have the following results:
The old chain wouldn't accept any transactions made for the new chain because it wouldn't attempt to calculate the signature hash with the extra "Hard Fork #123" data, so all signatures made for the new chain would look invalid to it.
The new chain wouldn't accept any transactions made for the old chain because they'd be missing the required "Hard Fork #123" data.
For most (probably all) wallets, adding "Hard Fork #123" to the data used to create the signature hash would be technically easy---but it does require the wallet author support the fork and that all users upgrade before the fork. More difficult (depending on the wallet) would be supporting both signature formats and perhaps allowing the user to choose between them. Still, I'd imagine it's not too hard.
However, most proposed hard forks for Bitcoin don't include this or any other direct replay protection. This is probably because their proposers think there will be a lower chance of adoption if developers and users have to take any action to use the hard fork.
Interestingly, the original 0.1 version of the Bitcoin protocol included three opcodes (OP_VER
, OP_VERIF
, and OP_VERNOTIF
) that could be used for replay protection during a hard fork by allowing you to specify what rules had to be followed to spend your transaction on different VERsions of the protocol.
Unfortunately, the design didn't work and Satoshi Nakamoto removed the opcodes from the protocol. In addition to providing replay protection after a hard fork, they could be used to cause a type of hard fork called a consensus failure. (And, if you're following along with current drama, it has not escaped the amusement of some people that Bitcoin's earliest protocol allowed a hard fork be triggered by a VER
.)
Incompatible transactions
So if replay protection is available, you could spend an output from either block A or block B on either chain, but you'd have to sign the transaction differently for each chain---ensuring that you could send funds on the original chain to Alice and the funds on the new chain to Bob.
Without replay protection, you have to send the funds on both chains at the same time because whatever transaction you create will be valid on both chains[*]. However, there are ways to create transactions that will only be valid on one chain even if replay protection isn't available---they're just harder:
Using coinbase coins: blocks C (original chain) and C' (new chain) have different coinbase transactions. (A coinbase transaction is the special transaction in a block that pays the miner for creating that block.) These transactions are only valid on their particular chain, and any transactions that descend from them are also only valid on their particular chain.
So if you're a miner or you know a miner, you just have to mix at least 1 satoshi from them with your spend from block A and your transaction will have ad hoc replay protection.
However, there's two problems with this: (1) you need to know a miner who's willing to help you out and (2) coinbase transactions aren't spendable for 100 blocks[*], so you'd have to wait for a while after the hard fork before you could start spending.
Conflicting transactions: if you create two different transactions and send them to the two different block chains, it's possible (but not guaranteed) that one transaction will be confirmed in block C and one transaction in block C'.
As long as blocks C and C' remain part of their respective block chains then any transactions that spend your transaction can only be part of their respective block chains.
Since there's no guarantee that you can split coins this way, it's usually a good idea to send both separate transactions to yourself so that there's no way you can lose money beyond the transaction fees. Also, there's a way to increase your chances of the coins being split:
On the chain with the highest block height, spend your coins to yourself using nLockTime to target the current block height.
When the transaction above confirms, spend your coins to yourself on the other chain with no nLockTime.
Assuming the different chains have even a modest difference in height, this works because your nLockTime transaction is only initially valid on the higher-height chain, so it can't immediately be added to the lower-height chain. (Credit: I first heard of a method like this from Peter Todd; I don't know if he originated it, nor if this is exactly the method he was thinking about---I had to guess at how it would work from him just saying "use nLockTime".)
A warning
Hard forks, especially those without replay protection, break many normal assumptions of Bitcoin wallets. As such, there's a significant risk that you will lose money if you spend or accept bitcoins during an ongoing hard fork. Please be careful.
[*] Hard forks can change any part of the system, so the generalizations made in this post may not apply to all cases. However, I've tried to make them applicable to most proposed hard forks that only change a few things, such as the perpetually-debated maximum block size/weight.