# Slashing Protection Database Interchange Format
## Changelog
It is recommended to only support the latest version of the spec.
**This document has been superseded by EIP-3076, available here:** https://eips.ethereum.org/EIPS/eip-3076
v5 (2020-10-23):
* Remove redundant `interchange_format` field
* Final draft before EIP
v4 (2020-09-17):
* Replace `minimal` format by applying new semantics to the `complete` format
v3 (2020-09-01):
* Allow `last_signed_block_slot` and `last_signed_attestation_{source,target}_epoch` to be `null` in the minimal format, to represent the case where a validator has not yet signed a block or attestation (thanks Paul Harris).
v2 (2020-08-31):
* Require all integers/slots/epochs to be quoted so that JavaScript compatibility issues are avoided
v1 (2020-08-18):
* Initial version
## Complete Format
A complete record of all blocks and attestations signed by a set of validators
```json
{
"metadata": {
"interchange_format_version": "5",
"genesis_validators_root": "0x04700007fabc8282644aed6d1c7c9e21d38a03a0c4ba193f3afe428824b3a673"
},
"data": [
{
"pubkey": "0xb845089a1457f811bfc000588fbb4e713669be8ce060ea6be3c6ece09afc3794106c91ca73acda5e5457122d58723bed",
"signed_blocks": [
{
"slot": "81952",
"signing_root": "0x4ff6f743a43f3b4f95350831aeaf0a122a1a392922c45d804280284a69eb850b"
},
{
"slot": "81951",
},
...
],
"signed_attestations": [
{
"source_epoch": "2290",
"target_epoch": "3007",
"signing_root": "0x587d6a4f59a58fe24f406e0502413e77fe1babddee641fda30034ed37ecc884d"
},
{
"source_epoch": "2290",
"target_epoch": "3008",
},
...
]
}
]
}
```
* `pubkey: BLSPubkey` is the BLS public key of the validator encoded as 0x-prefixed hex.
* `signed_blocks` is a list of objects with fields:
* `slot: Slot`, the slot of the block that was signed
* `signing_root: Root` (optional) is [`compute_signing_root(block, domain)`][csr], where:
* `block` is the block that was signed as type `BeaconBlock` or equivalently `BeaconBlockHeader`
* `domain` is equal to [`compute_domain(DOMAIN_BEACON_PROPOSER, fork, metadata.genesis_validators_root)`][cd], where:
* `metadata.genesis_validators_root` is the `genesis_validators_root` from this interchange file
* `fork: Version` is the fork that the block was signed against
* `signed_attestations` is a list of objects with fields:
* `source_epoch: Epoch`, the `attestation.data.source.epoch` of the signed attestation
* `target_epoch: Epoch`, the `attestation.data.target.epoch` of the signed attestation
* `signing_root: Root` (optional) is [`compute_signing_root(attestation, domain)`][csr], where:
* `attestation` is the attestation that was signed as type `AttestationData`
* `domain` is equal to [`compute_domain(DOMAIN_BEACON_ATTESTER, fork, metadata.genesis_validators_root)`][cd], where:
* `metadata.genesis_validators_root` is the `genesis_validators_root` from this interchange file
* `fork: Version` is the fork that the attestation was signed against
### Semantics
To support the role that the `minimal` format used to play, we impose some additional restrictions about signing messages less than the minimum block/attestation (points 2 and 4 below).
After importing an interchange file with data field `data`, a signer MUST:
1. Refuse to sign any block that is slashable with respect to the blocks contained in `data.signed_blocks`. For details of what constitutes a slashable block, see [process_proposer_slashing][pps]. If the `signing_root` is absent from a block, a signer must assume that any new block with the same slot is slashable with respect to the imported block.
2. Refuse to sign any block with `slot <= min(b.slot for b in data.signed_blocks if b.pubkey == proposer_pubkey)`, except if it is a repeat signing as determined by the `signing_root`.
3. Refuse to sign any attestation that is slashable with respect to the attestations contained in `data.signed_attestations`. For details of what constitutes a slashable attestation, see [is_slashable_attestation_data][isad].
4. Refuse to sign any attestation with:
- `source.epoch < min(att.source_epoch for att in data.signed_attestations if att.pubkey == attester_pubkey)`, OR
- `target_epoch <= min(att.target_epoch for att in data.signed_attestations if att.pubkey == attester_pubkey)`
The old `minimal` format can be emulated by outputting 0-1 attestations and blocks for each validator (no signing root required). For example, this `complete` interchange is now equivalent to the old `minimal` example shown below:
```json
{
"metadata": {
"interchange_format": "complete",
"interchange_format_version": "4",
"genesis_validators_root": "0x04700007fabc8282644aed6d1c7c9e21d38a03a0c4ba193f3afe428824b3a673"
},
"data": [
{
"pubkey": "0xb845089a1457f811bfc000588fbb4e713669be8ce060ea6be3c6ece09afc3794106c91ca73acda5e5457122d58723bed",
"signed_blocks": [ { "slot": "89765" } ],
"signed_attestations": [ { "source_epoch": "2990", "target_epoch": "3007" } ]
},
...
],
}
```
If a validator is yet to sign a block or attestation, the relevant list is simply left empty -- no more `null`!
[pps]: https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#proposer-slashings
[isad]: https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#is_slashable_attestation_data
[csr]: https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#compute_signing_root
[cd]: https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#compute_domain
## Old Minimal Format (v3)
NOT SUPPORTED AS OF v4 DRAFT OR LATER
Similar to Teku's native format, just 3 integers per validator:
```json
{
"metadata": {
"interchange_format": "minimal",
"interchange_format_version": "3",
"genesis_validators_root": "0x04700007fabc8282644aed6d1c7c9e21d38a03a0c4ba193f3afe428824b3a673"
},
"data": [
{
"pubkey": "0xb845089a1457f811bfc000588fbb4e713669be8ce060ea6be3c6ece09afc3794106c91ca73acda5e5457122d58723bed",
"last_signed_block_slot": "89765",
"last_signed_attestation_source_epoch": "2990",
"last_signed_attestation_target_epoch": "3007",
},
...
],
}
```
* `pubkey` is the BLS public key of the validator encoded as 0x-prefixed hex.
* `last_signed_block_slot: Slot` (optional) is the greatest slot of a block signed by `pubkey`. Can be `null` to indicate that no block has been signed.
* `last_signed_attestation_source_epoch: Epoch` (optional) is the greatest `attestation.data.source.epoch` of an `attestation` signed by `pubkey`. Can be `null` or absent.
* `last_signed_attestation_target_epoch: Epoch` (optional) is the greatest `attestation.data.target.epoch` of an `attestation` signed by `pubkey`. Can be `null` or absent.
It is an error for one of `last_signed_attestation_source_epoch` or `last_signed_attestation_target_epoch` to be `null`/absent, if the other is present.
## Test Cases
https://github.com/eth2-clients/slashing-protection-interchange-tests
## Possible Changes
Some breaking changes that could be worth pursuing with client consensus
* ~~Rename `last_signed_` fields to `greatest_signed_` or `highest_signed_` to clarify that it should not be the most _recently_ signed message, but the highest slot/epoch one.~~
* Hard-fork future proofing (list fork versions and slots in metadata)
* A hybrid of the minimal and complete formats that prevents signing messages before some point, with complete data for more recent epochs (DONE, this is the new v4 complete format)
## References
* Lighthouse's slashing protection DB schema: https://github.com/sigp/lighthouse/blob/9a97a0b14fdcd265769981a02e9cb37dac3b553a/validator_client/slashing_protection/src/slashing_database.rs#L52-L81
* Lighthouse's implementation of the format: https://github.com/sigp/lighthouse/pull/1544
* Lighthouse docs on import/export: https://lighthouse-book.sigmaprime.io/slashing-protection.html#import-and-export
* SPDIF not to be confused with [S/PDIF](https://en.wikipedia.org/wiki/S/PDIF)