Weekly Dev Report
Attended the Blockchain Workshops NYC and spoke rather briefly about Bitcoin… If you were there I think you might agree with me that allowing people to present slides at the beginning of a “panel” wasn’t a good idea.
Hard-fork discussion with the signers of the Hong Kong agreement (and others), specifically voting schemes.
Consensus Critical Voting Considerations
Here’s some considerations being discussed:
Privacy — Consistent voting patterns have the potential of linking coins together.
Blacklisting — Coins could be blacklisted based on them voting the “wrong” way.
Implementation Complexity — How much new code is needed, both to vote, and count the votes?
Efficiency — Both in terms of block-chain space, and network bandwidth.
Secondly, implementations are being discussed, which I think roughly fall into two main categories:
It’s technically quite simple to make every transaction a vote, e.g. by using bits in the per-txin nSequence field, or with extra transaction data (something segwit may allow in the future); nSequence is by far the simplest for both consensus code and wallets to implement.
However, this has both privacy and blacklisting downsides. The best we can do given the current state of crypto (no ZK-SNARKS) is randomly sample votes. In this method, the default behavior would be for txouts to be non-voting when spent unless H(txout:n + blkhash) < target. In English, we’d be using the block hash of the block containing the txout as a random number generator, with only a random subset of txouts - say 1% or 10% - being counted. This means that if you’re spending a txout, most of the time you don’t vote at all - leaving the voting field empty. The subset of times when you can vote do count, but linking together coins based on consistent voting patterns becomes harder. A big disadvantage of this from a social point of view is likely to be variance - if you are making transactions relatively infrequently, you might get unlucky and have very few opportunities to vote. It’d be nice to make the variance adjustable, but as txouts may be created by someone other than the user who wants to vote (when they’re not change) implementing that becomes very complex quite quickly (you’d have to make the variance setting part of the scriptPubKey, yuck).
It’s not clear how much this would discourage blacklisting, as votes are still publicly visible. On the other hand, if blacklisting is your threat model, we’ve probably got bigger things to worry about right now.
Here we’re talking about schemes where transactions themselves aren’t the vehicle for voting. Non-consensus coin voting already exists of course, in the form of sites like Bitcoinocracy; they work by having coin owners sign messages with their scriptPubKeys indicating their vote.
Unlike per-transaction votes, because these messages aren’t valid transactions, they can be signed with keys that can’t be used to spend the coins. For example, consider the following scriptPubKey:
IF <pubkey> CHECKSIG ELSE 499,999 CHECKLOCKTIMEVERIFY DROP <vote-pubkey> CHECKSIG ENDIF
Due to the CLTV in the second branch of the IF statement, vote-pubkey can only be used to sign transactions with nLockTime set to block height 499,999 - about 4,000 years into the future. Thus the voting pubkey can only be used to sign voting messages, not valid transactions. Equally, Johnson Lau suggested that one of the invalid opcodes could be used as well, which usefully generalizes to all kinds of message signing:
IF <pubkey> CHECKSIG ELSE <message class> OP_INVALID <msg-pubkey> CHECKSIG ENDIF
For example, you could imagine a Bitcoin exchange making use of this technique to keep the keys used for actually spending coins in cold storage, which still allowing solvency-audit-related messages to be signed on a more frequent basis (obviously, this may reduce the value of the solvency audit in some cases!).
However, is this relevant to consensus voting? For the vote to be actually enforced by consensus, the vote must be recorded in the block-chain itself; if it’s not recorded in the block-chain full nodes have no way of knowing if they have a full copy of all relevant votes. We also want a vote that’s weighted by something meaningful, like coin days destroyed; signing a message is free. However, this means we have a double-spend problem: we only want a given output to be allowed to vote once.
We’re not doing an message-based votes for bandwidth reasons: nSequence voting takes no extra space in transactions directly, and if extra transactions being made to vote is your concern, it’s easy to reduce that impact greatly with the probabilistic sampling technique mentioned above.
I also don’t think privacy is a good argument for off-chain techniques: without moon-math like ZK-SNARKs, the best we can do is again probabilistic sampling, and that technique is relevant regardless of how the votes are cast.
Blacklisting concerns are a reasonable reason for off-chain voting: by separating voting from spending coins we can vote well after spending, makes blacklisting harder to accomplish. But this means we can’t just add a new “has voted” flag to the UTXO set - we’re counting votes for UTXO’s that don’t exist anymore. Keeping a index of txouts that have voted is also completely untenable. Our only option is to set a delay where votes are only allowed to be counted in blocks X blocks after being spent, and that delay itself sets requirements on how soon we can prune blocks (for a reasonable implementation).
That’s not to mention all the other issues like the need for new P2P messages to pass votes around; wallets need to store votes, broadcasting them later; blocks need a new way of committing to votes; sybil attack on the network can now censor votes; etc.
I think our only reasonable option in the near future for consensus-enforced voting is the per-transaction, nSequence-based scheme, preferably using probabilistic sampling for privacy. It’d also be a reasonable idea to do a pre-deployment “trial run” to gage interest by designing a voting specification, and inviting holders to create transactions that cast votes (the IsStandard() rules currently say nothing about nSequence).
I wish there was a way to solve the blacklisting issue right now, but let’s look at it from another perspective: if blacklisting was effective right now, what would that say about Bitcoin? I don’t believe we’d see the big exchanges and merchants blacklisting coins based on block-size votes - the PR impact would be horrible, and it’d just drive business to more reasonable, anti-censorship, alternatives (we’re not even talking about illegal activity after all).
Now suppose miners tried to blacklist transactions. If only a few % of miners do it, it’s ineffective. On the other hand, if a significant % of miners are blacklisting transactions - say >30% - we’re already at the point where those miners are proving that Bitcoin is insecure due to mining centralization: those same miners could just as easily conspire to drive their competitors - possibly competitors with different opinions on the block-size debate - out of business via selfish mining. Do miners really want to risk the negative PR impact, and thus price impact, of proving to the world that Bitcoin is too centralized to be secure?