Skip to content

Tallying an election as SPV client

Introduction

SPV verification was originally described by Satoshi in the Bitcoin whitepaper. We explore how to tally an election trustlessly using an SPV (Simplified Payment Verification) client.

We will use this process for tallying vote taken from the multi option vote contract:

For every participant:

- Derive contract address
- Look up transactions *spending* from the address
    - Ignore transactions confirmed before begin height.
    - Ignore transactions confirmed after end height.
- If there are no transactions, the participant has not voted.
- Sort transactions by confirmed height, then transaction ID.
- For each transaction:
    - Locate the vote in the scriptSig
    - End if vote is valid.

We will verify that the data received from a server is correct. We will asume that the servers the client is querying is not witholding information.

A note on information witholding

Many SPV request, such as querying for transactions, are suspect to information witholding attack.

It is often possible to provide proofs to SPV clients that some information exists on the blockchain, but it is difficult to design a protocol that lets a client detect if a server is witholding responses.

This is generally mitigated by querying multiple independent servers or nodes on the network.

SPV tally using the Electrum protocol

Prerequisite to verifying transactions

The SPV client needs to be able to verify that a transaction is confirmed in a block on the network.

The client downloads all the block headers using the electrum method blockchain.block.headers. If the client has a hard-coded checkpoint at some height, this eletrum method will provide merkle proofs that the headers are part of the checkpointed chain.

If there are branches (above checkpoint), the client must verify the competing branches and follow the most-work-chain. That is the chain that has the most computing power used to build it.

The client must verify that the proof-of-work conditions are met for each header. This means that the client must understand the difficulty adjustment algortims used in the chain (above checkpoint).

Fetching the votes

The tallying process described in the introduction of this document has the following step:

List of transactions spending from a contract address

To get this list of transactions, we can use the electrum method blockchain.address.get_history. This gives a list of all transactions spending to or from the contract.

The relevant transactions need then be downloaded using blockchain.transaction.get. A downloaded transaction needs to be verified. It must be hashed and the hash compared to what you requested. Then it must be verified that it is confirmed in the block the server claims. This is done using by calling blockchain.transaction.get_merkle for a merkle proof. The proof is used to verify that the transaction hash is part of the merkle root hash present in the blockheader of the block it's confirmed in.

With the above verification possibilities the client has all the information it requires to tally and verify the election.