Why SPV Wallets won’t work for Proof-of-Stake without Trusted Parties

And how Phore solves this problem

Julian Meyer
3 min readJul 11, 2018

SPV wallets allow users to sync up only block headers and the transactions relating to them instead of syncing up every single transaction in the blockchain. This allows extremely fast sync times, mobile wallets, IoT wallets, and possibly even web wallets.

The Problem with SPV wallets on Proof-of-Stake Chains

You can’t validate staking inputs. If a user stakes 1 million coins and finds a block, there are two essential items for a client to validate: that the user actually has 1 million coins, and that the hash of the block header is less than the difficulty target.

Header ~= concat(txoutpoint, time)Assertions:
1. SHA256(txoutpoint + time) < difficulty * value
2. txoutpoint.value == value

SPV clients can’t validate either point because they do not know anything about anybody else’s transactions.

They need an external source to prove that the transaction outpoint actually is unspent and has the value the miner claims.

Most implementations (including our current marketplace wallet) rely on an external source to prove those two assertions.

Relying on a certain proportion of nodes to claim them is also insecure because nodes should be considered basically free (see Sybil Attack).

How Phore Solves the Problem

Phore solves the problem in two steps.

  1. Add a merkle root of every single “stakeable” outpoint to the block header. This means after 3 hours (minimum staking time), the transaction ID, output ID, and value are added to the merkle tree.
  2. Add a merkle branch proof of the input to the stake to every transaction. This essentially proves that the staker actually had a valid, unspent UTXO that had a certain value at a certain block.
Header ~= concat(utxo, time, UTXO merkle root, merkle branch proof)

We’re also restricting the minimum stake size to 100 PHR because we identified that as approximately the break-even point for stakers to run a computer staking. This makes the merkle tree provably smallish.

This system can prove the two assertions above.

Also note that the branch proof would have a maximum size of about 1.6 kilobytes:

2log(nodes) * length of node = 2log (SUPPLY/100) * (32 bytes + 4 bytes + 8 bytes) = 1529 bytes

And the worst-case calculation time:

2 * numNodes - 1 = 2 * (SUPPLY/100) - 1 = 339999 hashes per block = 0.1 seconds on a m3 CPU

Do understand these are absolute worst case scenarios. In reality, it should take 1–10 ms and the proof should be about 880 bytes.

Why Staking Won’t Work

Staking won’t work with our system nor any other PoS system in a secure fashion. If stakers want to use an SPV wallet to construct blocks, they are opening the network to security issues. They can’t validate any transactions, meaning that they MUST get the information from an outside source. The outside source could easily lie about whether a transaction is valid and stop stakers from finding any blocks. (If they include a transaction that is invalid, the block will not be accepted by the network)

One solution to this has been to use empty blocks instead. Generally, this could work, however stakers don’t have enough information to construct a new UTXO merkle tree as detailed above.

If the UTXO merkle tree was not in the header and the staker mined empty blocks, they’re still vulnerable to the same attack. As stated above, the staker needs to assume the two assertions above are true. This opens them up to the same attack of decreasing network difficulty by running nodes that serve invalid block data. (Any blocks mined by an SPV client in this case could be invalid causing network difficulty to decrease)

Any PoS coin that claims to have light/SPV staking is either extremely insecure or uses a centralized source of data.

--

--