From 4f69f15dadeed9995da8036e8e8afcefc9460b23 Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 26 Nov 2024 00:14:01 -0500 Subject: [PATCH 01/11] SIMD-0204: Slashable event verification --- .../0204-slashable-event-verification.md | 297 ++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 proposals/0204-slashable-event-verification.md diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md new file mode 100644 index 000000000..afb811a72 --- /dev/null +++ b/proposals/0204-slashable-event-verification.md @@ -0,0 +1,297 @@ +--- +simd: '0204' +title: Slashable event verification +authors: + - Ashwin Sekar +category: Standard +type: Core +status: Review +created: 2024-11-26 +feature: (fill in with feature tracking issues once accepted) +--- + +## Summary + +This proposal describes an enshrined on-chain program to verify proofs that a +validator committed a slashable infraction. This program creates reports on chain +for use in future SIMDs. + +**This proposal does not modify any stakes or rewards, the program will +only verify and log infractions.** + +## Motivation + +There exists a class of protocol violations that are difficult to detect synchronously, +but are simple to detect after the fact. In order to penalize violators we provide +a means to record these violations on chain. + +This also serves as a starting point for observability and discussions around the +economics of penalizing these violators. This is a necessary step to implement +slashing in the Solana Protocol. + +## New Terminology + +None + +### Feature flags + +`create_slashing_program`: + +- `sProgVaNWkYdP2eTRAy1CPrgb3b9p8yXCASrPEqo6VJ` + +## Detailed Design + +On the epoch boundary where the `create_slashing_program` feature flag is first +activated the following behavior will be executed in the first block for the new +epoch: + +1. Create a new program account at `S1ashing11111111111111111111111111111111111` + with an upgrade authority set to the system program + `11111111111111111111111111111111` + +2. Verify that the program account + `8sT74BE7sanh4iT84EyVUL8b77cVruLHXGjvTyJ4GwCe` has a verified build hash of + `` [\[1\]](#notes) + +3. Copy the contents of `8sT74BE7sanh4iT84EyVUL8b77cVruLHXGjvTyJ4GwCe` into + `S1ashing11111111111111111111111111111111111` + +This program (hereafter referred to as the slashing program) supports 2 +instructions `DuplicateBlockProof`, and `CloseProofReport`. + +`DuplicateBlockProof` requires 1 account: + +0. `proof_account`, expected to be previously intiialized with the proof data. + +`DuplicateBlockProof` has an instruction data of 48 bytes, containing: + +- `0x00`, a fixed-value byte acting as the instruction discriminator +- `offset`, an unaligned eight-byte little-endian unsigned integer indicating + the offset from which to read the proof +- `slot`, an unaligned eight-byte little-endian unsigned integer indicating the + slot in which the violation occured +- `node_pubkey`, an unaligned 32 byte array representing the public key of the + node which committed the violation + +We expect the contents of the `proof_account` when read from `offset` to +deserialize to a struct of two byte arrays representing the duplicate shreds. +The first 4 bytes correspond to the length of the first shred, and the 4 bytes +after that shred correspond to the length of the second shred. + +```rust +struct DuplicateBlockProofData { + shred1_length: u32, + shred1: &[u8], + shred2_length: u32, + shred2: &[u8] +} +``` + +`DuplicateBlockProof` aborts if: + +- The difference between the current slot and `slot` is greater than 1 epoch's + worth of slots as reported by the `Clock` sysvar +- `offset` is larger than the length of `proof_account` +- `proof_account[offset..]` does not deserialize cleanly to a + `DuplicateBlockProofData`. +- The resulting shreds do not adhere to the Solana shred format [\[2\]](#notes) + or are legacy shred variants. +- The resulting shreds specify a slot that is different from `slot`. +- The resulting shreds specify different shred versions. + +After deserialization the slashing program will attempt to verify the proof, by +checking that `shred1` and `shred2` constitute a valid duplicate proof for +`slot` and are correctly signed by `node_pubkey`. This is similar to logic used +in Solana's gossip protocol to verify duplicate proofs for use in fork choice. + +### Proof verification + +`shred1` and `shred2` constitute a valid duplicate proof if any of the following +conditions are met: + +- Both shreds specify the same index and shred type, however their payloads + differ +- Both shreds specify the same FEC set, however their merkle roots differ +- Both shreds specify the same FEC set and are coding shreds, however their + erasure configs conflict +- At least one shred is a coding shred, and its erasure meta indicates an FEC set + overlap. +- The shreds are data shreds with different indices and the shred with the lower + index has the `LAST_SHRED_IN_SLOT` flag set + +Note: We do not verify that `node_pubkey` was the leader for `slot`. Any node that +willingly signs duplicate shreds for a slot that they are not a leader for is +eligible for slashing. + +--- + +### Signature verification + +In order to verify that `shred1` and `shred2` were correctly signed by +`node_pubkey` we use instruction retrospection. + +Using the `Instructions` sysvar we verify that the previous two instructions of +this transaction are for the program ID +`Ed25519SigVerify111111111111111111111111111` + +For each of these instructions, verify the instruction data: + +- The first byte is `0x01` +- The second byte (padding) is `0x00` + +And then deserialize the remaining instruction data as 2 byte little-endian +unsigned integers: + +```rust +struct Ed25519SignatureOffsets { + signature_offset: u16, // offset to ed25519 signature of 64 bytes + signature_instruction_index: u16, // instruction index to find signature + public_key_offset: u16, // offset to public key of 32 bytes + public_key_instruction_index: u16, // instruction index to find public key + message_data_offset: u16, // offset to start of message data + message_data_size: u16, // size of message data + message_instruction_index: u16, // index of instruction data to get message + // data +} +``` + +We wish to verify that these instructions correspond to + +``` +verify(pubkey = node_pubkey, message = shred1.merkle_root, signature = shred1.signature) +verify(pubkey = node_pubkey, message = shred2.merkle_root, signature = shred2.signature) +``` + +We use the deserialized offsets to calculate [\[3\]](#notes) the `pubkey`, +`message`, and `signature` of each instruction and verify that they correspond +to the `node_pubkey`, `merkle_root`, and `signature` specified by the shred payload. + +If both proof and signer verification succeed, we continue on to store the incident. + +--- + +### Incident reporting + +After verifying a successful proof we store the results in a program derived +address for future use. The PDA is derived using the `node_pubkey`, `slot`, and +the violation type: + +```rust +let (pda, _) = find_program_address(&[ + node_pubkey.to_bytes(), + slot.to_le_bytes(), + ViolationType::DuplicateBlock.to_u8(), +]) +``` + +At the moment `DuplicateBlock` is the only violation type but future work will +add additional slashing types. + +If the `pda` account has non-zero lamports, then we abort as the violation has +already been reported. Otherwise we create the account, with the slashing program +as the owner. In this account we store the following: + +```rust +struct ProofReport { + reporter: Pubkey, // Fee payer, to allow the account to be closed + epoch: Epoch, // Epoch in which this report was created + pubkey: Pubkey, // The pubkey of the node that committed the violation + slot: Slot, // Slot in which the violation occured + violation_type: u8, // The violation type + proof: Vec // The serialized proof + proof_account: Option, // Optional account where proof is stored instead +} +``` + +The `DuplicateBlockProofData` is serialized into the `proof` field. This provides +an on chain trail of the reporting process, since the `proof_account` supplied in +the `DuplicateBlockProof` account could later be modified. + +The `pubkey` is populated with the `node_pubkey`. For future violation types that +involve votes, this will instead be populated with the vote account's pubkey. +The work in SIMD-0180 will allow the `node_pubkey` to be translated to a vote account +if needed. + +Note that PDA's can only be created with a 10kb initial size. +Although not a problem for `DuplicateBlockProofData`, if future proof types require +more space, we allow the proof to be stored in a separate account, and linked back +to the PDA using the `proof_account` field. + +--- + +### Closing the incident report + +After the slashing violation has been processed by the runtime, the initial fee +payer may wish to close their `ProofReport` account to reclaim the lamports. + +They can accomplish this via the `CloseProofReport` instruction which requires +2 accounts: + +0. `report_account`: The PDA account storing the report: Writable, owned by the + slashing program +1. `destination`: Writable account to reclaim the lamports + +`CloseProofReport` has an instruction data of 42 bytes, containing: + +- `0x01`, a fixed-value byte acting as the instruction discriminator +- `violation_type`, a one byte value acting as the violation type discriminator +- `slot`, an unaligned eight-byte little-endian unsigned integer indicating the + slot which was reported +- `pubkey`, an unaligned 32 byte array representing the public key of the node + which was reported + +We abort if: + +- `violation_type` is not `0x00` (corresponds to `DuplicateBlock` violation) +- Deriving the pda using `pubkey`, `slot`, and `ViolationType::DuplicateBlock` + as outlined above does not result in the adddress of `report_account` +- `report_account` is not writeable +- `report_account` does not deserialize cleanly to `ProofReport` +- `report_account.reporter` is not a signer +- `report_account.epoch + 3` is greater than the current epoch reported from + the `Clock` sysvar. We want to ensure that these accounts do not get closed before + they are observed by indexers and dashboards. + +Otherwise we close the `report_account` and credit the `lamports` to `destination` + +--- + +## Alternatives Considered + +This proposal deploys the slashing program in an "enshrined" account, only upgradeable +through code changes in the validator software. Alternatively we could follow the +SPL program convention and deploy to an account upgradeable by a multisig. This +allows for more flexibility in the case of deploying hotfixes or rapid changes, +however allowing upgrade access to such a sensitive part of the system via a handful +of engineers poses a security risk. + +## Impact + +A new program will be enshrined at `S1ashing11111111111111111111111111111111111`. + +Reports stored in PDAs of this program might be queried for dashboards which could +incur additional indexing overhead for RPC providers. + +## Security Considerations + +None + +## Drawbacks + +None + +## Backwards Compatibility + +The feature is not backwards compatible + +## Notes + +\[1\]: Sha256 of program data, see + https://github.com/Ellipsis-Labs/solana-verifiable-build/blob/214ba849946be0f7ec6a13d860f43afe125beea3/src/main.rs#L331 + for details. + +\[2\]: The slashing program will support any combination of merkle shreds, chained + merkle shreds, and retransmitter signed chained merkle shreds, see https://github.com/anza-xyz/agave/blob/4e7f7f76f453e126b171c800bbaca2cb28637535/ledger/src/shred.rs#L6 + for the full specification. + +\[3\]: Example of offset calculation can be found here https://docs.solanalabs.com/runtime/programs#ed25519-program From c8b42fc71422ac602c8b52fceb4f729303f51a79 Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 3 Dec 2024 13:57:30 -0500 Subject: [PATCH 02/11] pr feedback --- .../0204-slashable-event-verification.md | 77 ++++++++++++------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index afb811a72..852d69d6a 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -56,12 +56,18 @@ epoch: 3. Copy the contents of `8sT74BE7sanh4iT84EyVUL8b77cVruLHXGjvTyJ4GwCe` into `S1ashing11111111111111111111111111111111111` -This program (hereafter referred to as the slashing program) supports 2 -instructions `DuplicateBlockProof`, and `CloseProofReport`. +This is the only protocol change that clients need to implement. The remaining +proposal describes the function of this program, hereafter referred to as the +slashing program. -`DuplicateBlockProof` requires 1 account: +### Slashing Program -0. `proof_account`, expected to be previously intiialized with the proof data. +This slashing program supports two instructions `DuplicateBlockProof`, and +`CloseProofReport`. + +`DuplicateBlockProof` requires 1 account and the `Instructions` sysvar: + +0. `proof_account`, expected to be previously initialized with the proof data. `DuplicateBlockProof` has an instruction data of 48 bytes, containing: @@ -74,19 +80,22 @@ instructions `DuplicateBlockProof`, and `CloseProofReport`. node which committed the violation We expect the contents of the `proof_account` when read from `offset` to -deserialize to a struct of two byte arrays representing the duplicate shreds. +deserialize to two byte arrays representing the duplicate shreds. The first 4 bytes correspond to the length of the first shred, and the 4 bytes after that shred correspond to the length of the second shred. ```rust struct DuplicateBlockProofData { - shred1_length: u32, - shred1: &[u8], - shred2_length: u32, - shred2: &[u8] + shred1_length: u32 // Unaligned four-byte little-endian unsigned integer, + shred1: &[u8] // `shred1_length` bytes representing a shred, + shred2_length: u32 // Unaligned four-byte little-endian unsigned integer, + shred2: &[u8] // `shred2_length` bytes representing a shred, } ``` +Users are expected to populate the `proof_account` themselves, using an onchain +program such as the Record program. + `DuplicateBlockProof` aborts if: - The difference between the current slot and `slot` is greater than 1 epoch's @@ -104,7 +113,7 @@ checking that `shred1` and `shred2` constitute a valid duplicate proof for `slot` and are correctly signed by `node_pubkey`. This is similar to logic used in Solana's gossip protocol to verify duplicate proofs for use in fork choice. -### Proof verification +#### Proof verification `shred1` and `shred2` constitute a valid duplicate proof if any of the following conditions are met: @@ -125,10 +134,10 @@ eligible for slashing. --- -### Signature verification +#### Signature verification In order to verify that `shred1` and `shred2` were correctly signed by -`node_pubkey` we use instruction retrospection. +`node_pubkey` we use instruction introspection. Using the `Instructions` sysvar we verify that the previous two instructions of this transaction are for the program ID @@ -170,7 +179,7 @@ If both proof and signer verification succeed, we continue on to store the incid --- -### Incident reporting +#### Incident reporting After verifying a successful proof we store the results in a program derived address for future use. The PDA is derived using the `node_pubkey`, `slot`, and @@ -178,9 +187,9 @@ the violation type: ```rust let (pda, _) = find_program_address(&[ - node_pubkey.to_bytes(), - slot.to_le_bytes(), - ViolationType::DuplicateBlock.to_u8(), + node_pubkey.to_bytes(), // 32 byte array representing the public key + slot.to_le_bytes(), // Unsigned little-endian eight-byte integer + 0u8, // Byte representing the violation type ]) ``` @@ -193,13 +202,23 @@ as the owner. In this account we store the following: ```rust struct ProofReport { - reporter: Pubkey, // Fee payer, to allow the account to be closed - epoch: Epoch, // Epoch in which this report was created - pubkey: Pubkey, // The pubkey of the node that committed the violation - slot: Slot, // Slot in which the violation occured - violation_type: u8, // The violation type - proof: Vec // The serialized proof - proof_account: Option, // Optional account where proof is stored instead + reporter: Pubkey, // 32 byte array representing the pubkey of the + Fee payer, to allow the account to be closed + epoch: Epoch, // Unaligned unsigned eight-byte little endian + integer representing the epoch in which this + report was created + pubkey: Pubkey, // 32 byte array representing the pubkey of the + node that committed the violation + slot: Slot, // Unaligned unsigned eight-byte little endian + integer representing the slot in which the + violation occured + violation_type: u8, // Byte representing the violation type + proof_account: Pubkey, // 32 byte array representing the account where + the proof is stored + proof_size: u32, // Unaligned unsigned four-byte little endian + integer representing the size of the serialized + proof + proof: &[u8], // Byte array of the serialized proof } ``` @@ -219,10 +238,11 @@ to the PDA using the `proof_account` field. --- -### Closing the incident report +#### Closing the incident report -After the slashing violation has been processed by the runtime, the initial fee -payer may wish to close their `ProofReport` account to reclaim the lamports. +In a future SIMD the reports will be used for runtime processing. This is out of +scope, but after this period has passed, the initial fee payer may wish to close +their `ProofReport` account to reclaim the lamports. They can accomplish this via the `CloseProofReport` instruction which requires 2 accounts: @@ -245,14 +265,15 @@ We abort if: - `violation_type` is not `0x00` (corresponds to `DuplicateBlock` violation) - Deriving the pda using `pubkey`, `slot`, and `ViolationType::DuplicateBlock` as outlined above does not result in the adddress of `report_account` -- `report_account` is not writeable +- `report_account` is not owned by the slashing program - `report_account` does not deserialize cleanly to `ProofReport` - `report_account.reporter` is not a signer - `report_account.epoch + 3` is greater than the current epoch reported from the `Clock` sysvar. We want to ensure that these accounts do not get closed before they are observed by indexers and dashboards. -Otherwise we close the `report_account` and credit the `lamports` to `destination` +Otherwise we set the owner of `report_account` to the system program, rellocate +the account to 0 bytes, and credit the `lamports` to `destination` --- From b980cb1f6b68e804a2153f9c36fc8c0ff004c93a Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 3 Dec 2024 14:01:27 -0500 Subject: [PATCH 03/11] make close account permissionless --- proposals/0204-slashable-event-verification.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index 852d69d6a..a0d48aea5 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -245,35 +245,25 @@ scope, but after this period has passed, the initial fee payer may wish to clos their `ProofReport` account to reclaim the lamports. They can accomplish this via the `CloseProofReport` instruction which requires -2 accounts: +one account: 0. `report_account`: The PDA account storing the report: Writable, owned by the slashing program -1. `destination`: Writable account to reclaim the lamports -`CloseProofReport` has an instruction data of 42 bytes, containing: +`CloseProofReport` has an instruction data of one byte, containing: - `0x01`, a fixed-value byte acting as the instruction discriminator -- `violation_type`, a one byte value acting as the violation type discriminator -- `slot`, an unaligned eight-byte little-endian unsigned integer indicating the - slot which was reported -- `pubkey`, an unaligned 32 byte array representing the public key of the node - which was reported We abort if: -- `violation_type` is not `0x00` (corresponds to `DuplicateBlock` violation) -- Deriving the pda using `pubkey`, `slot`, and `ViolationType::DuplicateBlock` - as outlined above does not result in the adddress of `report_account` - `report_account` is not owned by the slashing program - `report_account` does not deserialize cleanly to `ProofReport` -- `report_account.reporter` is not a signer - `report_account.epoch + 3` is greater than the current epoch reported from the `Clock` sysvar. We want to ensure that these accounts do not get closed before they are observed by indexers and dashboards. Otherwise we set the owner of `report_account` to the system program, rellocate -the account to 0 bytes, and credit the `lamports` to `destination` +the account to 0 bytes, and credit the `lamports` to `report_account.reporter` --- From bd9d399365f39aa0bb1ff22679029e0872e83ff7 Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 3 Dec 2024 14:03:04 -0500 Subject: [PATCH 04/11] spell out three epoch window rational --- proposals/0204-slashable-event-verification.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index a0d48aea5..8458a697a 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -262,6 +262,10 @@ We abort if: the `Clock` sysvar. We want to ensure that these accounts do not get closed before they are observed by indexers and dashboards. +The three epoch window is somewhat arbitrary, we only need the `report_account` to +last at least one epoch in order to for it to be observed by the runtime as part +of a future SIMD. + Otherwise we set the owner of `report_account` to the system program, rellocate the account to 0 bytes, and credit the `lamports` to `report_account.reporter` From 0d133749c8f92629f981679b4ad913e3e0f1d097 Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 3 Dec 2024 14:05:25 -0500 Subject: [PATCH 05/11] duplicate proof -> duplicate block proof --- proposals/0204-slashable-event-verification.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index 8458a697a..7fe2aedc6 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -109,14 +109,14 @@ program such as the Record program. - The resulting shreds specify different shred versions. After deserialization the slashing program will attempt to verify the proof, by -checking that `shred1` and `shred2` constitute a valid duplicate proof for +checking that `shred1` and `shred2` constitute a valid duplicate block proof for `slot` and are correctly signed by `node_pubkey`. This is similar to logic used -in Solana's gossip protocol to verify duplicate proofs for use in fork choice. +in Solana's gossip protocol to verify duplicate block proofs for use in fork choice. #### Proof verification -`shred1` and `shred2` constitute a valid duplicate proof if any of the following -conditions are met: +`shred1` and `shred2` constitute a valid duplicate block proof if any of the +following conditions are met: - Both shreds specify the same index and shred type, however their payloads differ From 472c2b4c37b86d0187f677282640cc2c7469bb1d Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 3 Dec 2024 15:17:19 -0500 Subject: [PATCH 06/11] remove lamport check in favor of data check --- proposals/0204-slashable-event-verification.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index 7fe2aedc6..72d93e56b 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -196,9 +196,9 @@ let (pda, _) = find_program_address(&[ At the moment `DuplicateBlock` is the only violation type but future work will add additional slashing types. -If the `pda` account has non-zero lamports, then we abort as the violation has -already been reported. Otherwise we create the account, with the slashing program -as the owner. In this account we store the following: +If the `pda` account has any data and is owned by the slashing program, then we +abort as the violation has already been reported. Otherwise we create the account, +with the slashing program as the owner. In this account we store the following: ```rust struct ProofReport { From c47359f7ff171320e97f32f29e9b9fbde46a0f6f Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Wed, 4 Dec 2024 13:27:12 -0500 Subject: [PATCH 07/11] instructions sysvar --- proposals/0204-slashable-event-verification.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index 72d93e56b..66aa6014e 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -68,6 +68,7 @@ This slashing program supports two instructions `DuplicateBlockProof`, and `DuplicateBlockProof` requires 1 account and the `Instructions` sysvar: 0. `proof_account`, expected to be previously initialized with the proof data. +1. `instructions`, Instructions sysvar `DuplicateBlockProof` has an instruction data of 48 bytes, containing: From f4f8ab7a66a95f60d5a267246629a9498bc316dc Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 17 Dec 2024 18:24:22 -0500 Subject: [PATCH 08/11] specify the default loader, and move program-data --- proposals/0204-slashable-event-verification.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index 66aa6014e..406aa1a41 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -46,8 +46,8 @@ activated the following behavior will be executed in the first block for the new epoch: 1. Create a new program account at `S1ashing11111111111111111111111111111111111` - with an upgrade authority set to the system program - `11111111111111111111111111111111` + owned by the default upgradeable loader with an upgrade authority set to the + system program `11111111111111111111111111111111` 2. Verify that the program account `8sT74BE7sanh4iT84EyVUL8b77cVruLHXGjvTyJ4GwCe` has a verified build hash of @@ -56,6 +56,9 @@ epoch: 3. Copy the contents of `8sT74BE7sanh4iT84EyVUL8b77cVruLHXGjvTyJ4GwCe` into `S1ashing11111111111111111111111111111111111` +4. Additionally copy the program-data account from `8sT74BE7sanh4iT84EyVUL8b77cVruLHXGjvTyJ4GwCe` + to the PDA for `S1ashing11111111111111111111111111111111111` + This is the only protocol change that clients need to implement. The remaining proposal describes the function of this program, hereafter referred to as the slashing program. From caf905835be80d97e219129bd3a3839aae968175 Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Tue, 17 Dec 2024 18:26:09 -0500 Subject: [PATCH 09/11] pr feedback: lower shred is coding for overlap --- proposals/0204-slashable-event-verification.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index 406aa1a41..60aaeeb12 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -127,8 +127,8 @@ following conditions are met: - Both shreds specify the same FEC set, however their merkle roots differ - Both shreds specify the same FEC set and are coding shreds, however their erasure configs conflict -- At least one shred is a coding shred, and its erasure meta indicates an FEC set - overlap. + The shreds specify different FEC sets, the lower index shred is a coding shred, + and its erasure meta indicates an FEC set overlap. - The shreds are data shreds with different indices and the shred with the lower index has the `LAST_SHRED_IN_SLOT` flag set From f89a01ba5262bb8b2e79d79f373a84e2dd534d3a Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Wed, 18 Dec 2024 15:21:17 -0500 Subject: [PATCH 10/11] pr feedback: use separate destination account for closing report --- proposals/0204-slashable-event-verification.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index 60aaeeb12..e5ea6c70d 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -73,7 +73,7 @@ This slashing program supports two instructions `DuplicateBlockProof`, and 0. `proof_account`, expected to be previously initialized with the proof data. 1. `instructions`, Instructions sysvar -`DuplicateBlockProof` has an instruction data of 48 bytes, containing: +`DuplicateBlockProof` has an instruction data of 81 bytes, containing: - `0x00`, a fixed-value byte acting as the instruction discriminator - `offset`, an unaligned eight-byte little-endian unsigned integer indicating @@ -82,6 +82,9 @@ This slashing program supports two instructions `DuplicateBlockProof`, and slot in which the violation occured - `node_pubkey`, an unaligned 32 byte array representing the public key of the node which committed the violation +- `destination`, an unaligned 32 byte array representing the account to reclaim + the lamports if a successful slashing report account is created and then later + closed. We expect the contents of the `proof_account` when read from `offset` to deserialize to two byte arrays representing the duplicate shreds. @@ -207,7 +210,10 @@ with the slashing program as the owner. In this account we store the following: ```rust struct ProofReport { reporter: Pubkey, // 32 byte array representing the pubkey of the - Fee payer, to allow the account to be closed + Fee payer, who reported this violation + destination: Pubkey, // 32 byte array representing the account to + credit the lamports when this proof report + is closed. epoch: Epoch, // Unaligned unsigned eight-byte little endian integer representing the epoch in which this report was created @@ -271,7 +277,7 @@ last at least one epoch in order to for it to be observed by the runtime as part of a future SIMD. Otherwise we set the owner of `report_account` to the system program, rellocate -the account to 0 bytes, and credit the `lamports` to `report_account.reporter` +the account to 0 bytes, and credit the `lamports` to `report_account.destination` --- From 245bd012f83b95f222ce407dfe26a97fafcfc859 Mon Sep 17 00:00:00 2001 From: Ashwin Sekar Date: Wed, 18 Dec 2024 17:11:19 -0500 Subject: [PATCH 11/11] Add chained merkle root condition --- proposals/0204-slashable-event-verification.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/proposals/0204-slashable-event-verification.md b/proposals/0204-slashable-event-verification.md index e5ea6c70d..859ec7778 100644 --- a/proposals/0204-slashable-event-verification.md +++ b/proposals/0204-slashable-event-verification.md @@ -130,8 +130,10 @@ following conditions are met: - Both shreds specify the same FEC set, however their merkle roots differ - Both shreds specify the same FEC set and are coding shreds, however their erasure configs conflict - The shreds specify different FEC sets, the lower index shred is a coding shred, - and its erasure meta indicates an FEC set overlap. +- The shreds specify different FEC sets, the lower index shred is a coding shred, + and its erasure meta indicates an FEC set overlap +- The shreds specify different FEC sets, the lower index shred has a merkle root + that is not equal to the chained merkle root of the higher index shred - The shreds are data shreds with different indices and the shred with the lower index has the `LAST_SHRED_IN_SLOT` flag set