-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add duplicate block proof sigverify #5
base: main
Are you sure you want to change the base?
Conversation
b28a6da
to
37888b9
Compare
program/src/instruction.rs
Outdated
@@ -79,10 +115,11 @@ pub(crate) fn decode_instruction_type(input: &[u8]) -> Result<SlashingInstructio | |||
|
|||
/// Utility function for decoding instruction data | |||
pub(crate) fn decode_instruction_data<T: Pod>(input_with_type: &[u8]) -> Result<&T, ProgramError> { | |||
if input_with_type.len() != pod_get_packed_len::<T>().saturating_add(1) { | |||
let data_len = pod_get_packed_len::<T>().saturating_add(1); | |||
if input_with_type.len() < data_len { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this to <
to allow storage of the sigverify data in slashing instruction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If DuplicateBlockProofSigverifyData
is directly included in DuplicateBlockProofInstructionData
, then this shouldn't be an issue!
37888b9
to
50f1118
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really great work! The design makes sense of including the sigverify offsets directly in the slashing instruction, and you've matched everything up without duplication. My comments are mostly minor
program/src/instruction.rs
Outdated
slot: Slot, | ||
node_pubkey: Pubkey, | ||
sigverify_data: &DuplicateBlockProofSigverifyData, | ||
slashing_instruction_index: u16, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'm thinking this should be left out for now for easier usage, but the doc comment can certainly call out that these must be the first two instructions in a transaction. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ya good suggestion, updated here 074e0b3
program/src/instruction.rs
Outdated
/// Utility struct for packaging the signature verification data required | ||
/// for `SlashingInstruction::DuplicateBlockProof` | ||
#[repr(C)] | ||
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] | ||
pub struct DuplicateBlockProofSigverifyData { | ||
/// The first shred's merkle root (the message of the first sigverify | ||
/// instruction) | ||
pub shred_1_merkle_root: Hash, | ||
/// The first shred's signature (the signature of the first sigverify | ||
/// instruction) | ||
pub shred_1_signature: [u8; SIGNATURE_BYTES], | ||
/// The second shred's merkle root (the message of the second sigverify | ||
/// instruction) | ||
pub shred_2_merkle_root: Hash, | ||
/// The second shred's signature (the signature of the second sigverify | ||
/// instruction) | ||
pub shred_2_signature: [u8; SIGNATURE_BYTES], | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for not including this in DuplicateBlockProofInstructionData
? It would be clearer to show that this needs to be part of the instruction data. Or at the very least, add a comment in DuplicateBlockProofInstructionData
saying that it will be followed by this type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duh that's so much easier haha, updated here 884d9ee
program/src/instruction.rs
Outdated
@@ -79,10 +115,11 @@ pub(crate) fn decode_instruction_type(input: &[u8]) -> Result<SlashingInstructio | |||
|
|||
/// Utility function for decoding instruction data | |||
pub(crate) fn decode_instruction_data<T: Pod>(input_with_type: &[u8]) -> Result<&T, ProgramError> { | |||
if input_with_type.len() != pod_get_packed_len::<T>().saturating_add(1) { | |||
let data_len = pod_get_packed_len::<T>().saturating_add(1); | |||
if input_with_type.len() < data_len { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If DuplicateBlockProofSigverifyData
is directly included in DuplicateBlockProofInstructionData
, then this shouldn't be an issue!
program/src/duplicate_block_proof.rs
Outdated
pub(crate) expected_shred1_merkle_root: &'a Hash, | ||
pub(crate) expected_shred2_merkle_root: &'a Hash, | ||
pub(crate) expected_shred1_signature: &'a [u8; SIGNATURE_BYTES], | ||
pub(crate) expected_shred2_signature: &'a [u8; SIGNATURE_BYTES], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiny nit: can this be laid out in the same order as the instruction? That way you could eventually just cast the instruction data to this type and avoid doing any work to create it, ie
pub(crate) expected_shred1_merkle_root: &'a Hash, | |
pub(crate) expected_shred2_merkle_root: &'a Hash, | |
pub(crate) expected_shred1_signature: &'a [u8; SIGNATURE_BYTES], | |
pub(crate) expected_shred2_signature: &'a [u8; SIGNATURE_BYTES], | |
pub(crate) expected_shred1_merkle_root: &'a Hash, | |
pub(crate) expected_shred1_signature: &'a [u8; SIGNATURE_BYTES], | |
pub(crate) expected_shred2_merkle_root: &'a Hash, | |
pub(crate) expected_shred2_signature: &'a [u8; SIGNATURE_BYTES], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep done here b5b5b0f
just cast the instruction data to this type and avoid doing any work to create it
For this are you suggesting that we don't actually copy the data over when doing the instruction introspection but instead just cast the instruction data?
program/src/duplicate_block_proof.rs
Outdated
@@ -243,17 +320,82 @@ fn check_shreds(slot: Slot, shred1: &Shred, shred2: &Shred) -> Result<(), Slashi | |||
Err(SlashingError::InvalidErasureMetaConflict) | |||
} | |||
|
|||
/// Verify that `shred1` and `shred2` are correctly signed by `node_pubkey`. | |||
/// Leader's sign the merkle root of each shred with their pubkey. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
micro nit typo
/// Leader's sign the merkle root of each shred with their pubkey. | |
/// Leaders sign the merkle root of each shred with their pubkey. |
program/src/duplicate_block_proof.rs
Outdated
// Hack to simulate the merkle roots being stored in instruction data | ||
let expected_shred1_merkle_root = | ||
unsafe { &*Box::into_raw(Box::new(shred1.merkle_root().unwrap_or_default())) }; | ||
let expected_shred2_merkle_root = | ||
unsafe { &*Box::into_raw(Box::new(shred2.merkle_root().unwrap_or_default())) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it's only testing, but this is a bit brittle, no? If the underlying Hash
ever gets cleaned up we'll get hard-to-reproduce memory issues during testing.
I appreciate it's more annoying to use, but do you mind passing in the merkle root refs as extra parameters to the function? That way we can avoid doing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep good call I was just lazy haha ff6e4de
program/src/duplicate_block_proof.rs
Outdated
assert!(proof_data | ||
.verify_proof(context, SLOT, &leader_pubkey) | ||
.is_ok()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I typically prefer doing an unwrap() to get a better error message if something goes wrong, ie
assert!(proof_data | |
.verify_proof(context, SLOT, &leader_pubkey) | |
.is_ok()); | |
proof_data | |
.verify_proof(context, SLOT, &leader_pubkey) | |
.unwrap(); |
assert!( | ||
ErasureMeta::check_erasure_consistency(&shred1, &shred2), | ||
"Expected erasure consistency failure", | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean to remove this check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it's not completely accurate to say it's an erasure consistency failure here, the real failure is the merkle root of shred1 and shred2 will not be consistent. i've updated the condition here.
Adds signature verification of the shreds included in a duplicate block proof to the slashing program.
Due to the limitations of zerocopying from the instructions sysvar the requirements are as follows:
shred1
and the second forshred2
as indicated by the ordering in theproof_account
specified to the slashing instruciton(pubkey, message, signature)
data indicated by the Ed25519 ix's offsets must be in the instruction data for the slashing instruction.If each
(pubkey, message, signature)
matches the(node_pubkey, shredx.merkle_root, shredx.signature)
for both shreds, then the signature verification is considered successful.Additionally we expose a utility for the user to create both the sigverify instruction and the slashing instruction together.
Will update the SIMD if this approach is satisfactory