I started this as a reply to the "zero-confirmation is not safe" thread, but i believe it warrants it's own thread.
Therefore, we are adapting ourselves (and letting others adapt) to a false reality by designing systems with an assumption that there is some security in zero-conf transactions. I'd much rather just write it off completely, and let businesses and users adapt to the idea that zero-conf transactions are basically useless for exchanges between untrusted parties. Forget it. If you don't trust the person, don't mess with zero-confirmation transactions. Period.
This is generally a solid design principle: when something is to break, you should make the failure visible and document it clearly so the user understands this is not the intended use of the software.
However, in this particular case
zero confirmation can be fixed so they are almost as secure as 1-confirmation payments with minimal tweaks to the client rules, a much more worthy goal than breaking them completely.
Tweak 1. Don't silently discard double spend transactions. Forward them along to other peers, marked as double spends
(*. This is essentially the same solution as in the
Two bitcoins for the price of one paper. They suggest hijacking the Bitcoin "alert" for this purpose, but I think the marking need not be explicit: you just need to always prefix the doublespend with the first spend when forwarding along to other peers, implicitly communicating the correct order. So if they haven't seen any of the transactions yet, they will inherit the same order as you, just as it happens today.
This kills in the bud all race attacks, where the merchant is unaware that a fraction of the miners have received and are actively extending a double spend. After you received the first zero-conf transaction, you listen 10 seconds for another txn attempting a double spend and if none is received you have a very high certainty that all honest miners have received that transaction and are actively mining it. The propagation time is on the order of 3 seconds so if the attacker sends the 2nd spend after 10 seconds the probability it would reach any miner first is zero.
So we are down to a Finney attack. (or an involuntary Finney where the attacker interferes with a miner's network connectivity so as to present it a different spend order)
Tweak 2. Don't obliviously extend blocks containing a double spend. When selecting the longest subchain to extend, blocks containing a known double spend
should be assigned a zero or negative difficulty. All other things being equal, a miner would chose to extend a 2 blocks subchain rather than a 3 block subchain the first of which contains what he can recognize as a double spend.
This will not fork the chain: if what we believe to be the double-spend subchain grows faster than our original choice, at some point we will concede that we were wrong and the network has a different view of what was the legitimate spend, so convergence will eventually be reached. The "some point" where this happens is determined by the negative difficulty we assign the double spend block. A small negative value will allow the work from the Finney attack block to simply be ignored by the majority of honest nodes, making the attack very costly in terms of resources and BTC potentially lost.
(**It's also stable in the Byzantine-Altruistic-Rational paradigm: if we are confident on our determination regarding what is the legitimate spend, then we are confident most other miners have the same idea because of tweak 1. Thus it's rational for us not to extend the block containing the double spend, due to the negative difficulty impact it would have on our work for the point of view of most other miners. When enough miners are altruistic and implement Tweak 2, it becomes irrational not to implement it and a rational majority will maintain the status quo.
Together, tweaks 1 and 2 rise the bar immensely for zero-confirmation attacks,. When 10 seconds have passed since the initial broadcast, we are fairly certain
the vast majority of miners are on our side and will actively fight a Finney attack because it's profitable for them to do so. When the attacker gets the merchandise from the store and broadcasts it's Finney block, all nodes learn about the double spend within it and rationally chose not to extend it (they should also carve out the 2nd spend from the Finney block and broadcast it, so the merchant learns about what just happened).
To surpass the penalty, in the small negative penalty scenario, the attacker needs to mine two blocks, the first of which is the Finney block. The probability for this to happen is on the order of (his ratio of hash power)^2, forcing him to do many double spends at the same time to have any chance of recovering the costs. So any vending machine could accept the zero confirmation payment with no risk and no need for observers or bribing miners to get on their side.
*) Naive implementation could open a potential denial of service, a rogue node sending over and over double spends of the same transaction. So you need to forward just one 2nd spend, not any of the following. The merchant needs to know that a double spend is in progress, not it's details, so races among 2nd, 3rd... spends are irrelevant. If any of the racing doublespends arrive at him, he fails the sale and holds the merchandise.
**) What about a large negative penalty, worth one or more blocks average difficulty ? It would make double spends attacks even harder requiring private mining of 3 or more chained blocks; but at some point reorgs are slower and deeper with many orphans, negating the benefits.