The first important thing to understand is that this method is one of two different ways of moving coins back and forth between two chains. The other is called Federated Peg, which I believe will be more successful despite being less technically sophisticated and more centralized.
General concept
The first step is that you send a transaction on the sidechain that locks your money in place. Once that transaction has a few confirmations, you create the SPV proof to send to the mainchain.
Let's go into more detail about that last step:
When you run an SPV client, your client doesn't download full blocks. It downloads headers. Then, it downloads the transactions to or from your wallet. Then, it downloads the merkle branches to connect your transaction to one of the block headers.
When you create an SPV proof, you take those block headers that you downloaded, and those merkle branches that you need to connect to your transaction, and your special coin-locking transaction, and you serialize them into a single datastructure.
Why do we need to serialize the SPV proof at all?
…can't the nodes checking the SPV proof ask nodes on the sidechain to provide the SPV data?
No, because the sidechain nodes might reply differently to different mainchain nodes. That would result in a fork of the mainchain. A serialized SPV proof will be evaluated the same way by all mainchain nodes.
Some complications
SPV proof might not match sidechain network
If I have lots of mining power, I don't need to have money on the sidechain in order to withdraw money from sidechain outputs on the mainchain. (i.e. I can fake a sidechain withdrawal.)
This is how it works: I create a transaction from a fake output on the sidechain. If I broadcasted this to the sidechain, all of the nodes would reject it. However, I mine a block containing this transaction, and I keep going until I get enough blocks that the mainchain will trust my SPV proof.
Mitigations
- Require more confirmations before moving money from sidechain to mainchain
- Create a grace period where someone can block your withdrawal by creating a 'counter SPV proof,' which shows a longer chain of proof of work that does not include your block header.
- When the sidechain detects that someone successfully stole money, it marks down all future withdrawals to avoid a bank run.
What you're depositing won't match what you're withdrawing
If you're using the sidechain for transactions, you're going to wind up with more or less than when you started. However, this is a softfork, so we can't just deposit all of the incoming funds into a single pot. All of the funds are spread around many different outputs, and in Bitcoin, you need to entirely spend any output you claim. (You can't partially claim an output.) There are two solutions to this:
Lock up the exact amount of money of an output on the mainchain, then claim that. Potentially do this many times. This is simple, but has two problems: first, it uses more blockchain space than nessary; second, if there is no set of outputs that add up precisely to what you're withdrawing, some of your money will be stuck in the sidechain.
Allow people to claim one or more outputs, and optionally send change to another OP_SPVPROOFVERIFY output. This solution is much more flexible, but has some hidden teeth. (Can you accidentally send an 80 BTC miner fee because you screwed up your javascript? Will people have an incentive to avoid the dust outputs, leading to a bunch of outputs that nobody wants to pay to redeem?)
Things that aren't complications
Nodes on the mainchain that don't understand OP_SPVPROOFVERIFY
Since this is a softfork, not all nodes have to upgrade.
What can be changed in a sidechain?
Since we're supposing that we're designing a new opcode from scratch, we can make it support many different things. It could support Scrypt, X11, whatever hashing algorithm we want. It can't support pure Proof of Stake in a meaningful way. It could support multiple different target times, address types, etc.
However, it can't support unanticipated changes, so if someone comes up with a brilliant change that's visible to SPV clients, it won't work with the above.
Well, that's not entirely true. You could create two instructions, OP_SPVPROOFCHECKERREGISTER, and OP_SPVPROOFVERIFY. The first one would register an ethereum-like script that could keep state, and would check all incoming redemption requests. The second would commit a sum of money until the former script said that it could be unlocked. That would allow arbitrary SPV proof systems (although it still wouldn't allow pure PoS systems) at the cost of increased complexity.