## Casper-FFG: Mitigating spam votes with NULL_SENDER ### Problem Statement Casper-FFG introduces a new concept of `vote` messages. While structured the same way as normal messages, a `vote` message is a special protocol message generated and sent by Casper validators. These votes messages determine the finality of the blockchain and therefore are processed differently from normal messages. In practice, a normal transaction is executed by the miner based on its gasPrice and the correct order of the account nonce. A vote transaction should be executed without censorship and has a higher priority than normal transactions. If we treat these two types of transactions the same way, normal transactions could block vote transactions from being processed. This is not the desired outcome. ### Background The AMIS team is trying to implement Casper-FFG on the geth client per [EIP1011](https://eips.ethereum.org/EIPS/eip-1011). Our understanding is that by using `NULL_SENDER`, Casper votes are not subject to price/nonce ordering like normal transactions. ### Issue When implementing `NULL_SENDER` mechanism in the geth client, we found the issue of spam votes difficult to mitigate. Zero-gas votes encourages spams. Benign validators that are hacked or use poorly-written code may misbehave. As a result, the client implementation needs to code against spam votes. Specifically, the client cannot execute vote transactions without placing a cap. Because a failed vote doesn’t count towards `vote_gas_used`, a miner can find itself executing failed votes indefinitely and, as a result, unable to produce the next block. We found ourselves asking the contract developers for a public function `votable()` to allow the client to validate a vote a priori. The client then can only place valid votes in its vote queue. These votes will later be EVM-executed and included in the next block. However, this does NOT free us completely from worrying about spam votes. Let’s suppose there are `N` ways a vote can fail in the Casper contract, and the client is able to screen `M` scenarios. There are still `N-M` ways that a vote can fail at EVM execution time. A block will still be delayed if * The network is spammed with votes that fail in those `N-M` ways * EVM keeps executing these failed vote without counting them towards `vote_gas_used` or placing a cap Even if the Casper contract guarantees `votable()` to capture all N failure modes, in the name of defensive programming where we don’t fully trust contract correctness, the client implementation will still want to cap vote processing to a fixed number or count failed votes towards `vote_gas_used`. ### Proposal We think it simpler if we can disincentivize spam votes all together. We propose the following: * A validator signs a vote transaction with its private key. This is simply the signature of the vote sender, and does NOT affect the validation code scheme in the Casper contract. * A validator uses a dedicated private key for vote transactions and not any other transactions. * Charge just enough gas for votes to discourage spam, or alternatively charge gas for failed votes only. * A vote transaction can be identified by * to == `CASPER_ADDR` * transaction data starts with vote bytes `0xe9dc0614` We recognize that in this scheme, if a validator uses the same private key for sending both normal and vote transactions, the votes can be blocked for having a higher nonce. But we believe that validators are disincentivized to do so since they will be slashed if they fail to vote promptly. Apart from removing the error case of spam votes, this approach also makes the client implementation simpler in two ways: * We don’t have to special case `NULL_SENDER` in various places of the code * The assumption of `NULL_SENDER` will not be used for scenarios other than Casper votes gnaws at a developer