From ca1820606d2f91d10851687d4014e76c85893e66 Mon Sep 17 00:00:00 2001 From: Hardhat Chad Date: Sun, 14 Apr 2024 06:03:32 +0000 Subject: [PATCH] remove hash arg and move nonce to front of digest --- Cargo.lock | 2 +- src/instruction.rs | 4 +--- src/processor/mine.rs | 51 +++++++++---------------------------------- tests/test_mine.rs | 34 ++++++++++------------------- 4 files changed, 24 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1f4937..60533b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2366,7 +2366,7 @@ dependencies = [ [[package]] name = "ore-program" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bs58 0.5.0", "bs64", diff --git a/src/instruction.rs b/src/instruction.rs index ca052d7..fa60d43 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -118,7 +118,6 @@ pub struct RegisterArgs { #[repr(C)] #[derive(Clone, Copy, Debug, Pod, Zeroable)] pub struct MineArgs { - pub hash: Hash, pub nonce: [u8; 8], } @@ -208,7 +207,7 @@ pub fn register(signer: Pubkey) -> Instruction { } /// Builds a mine instruction. -pub fn mine(signer: Pubkey, bus: Pubkey, hash: Hash, nonce: u64) -> Instruction { +pub fn mine(signer: Pubkey, bus: Pubkey, nonce: u64) -> Instruction { let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0; Instruction { program_id: crate::id(), @@ -222,7 +221,6 @@ pub fn mine(signer: Pubkey, bus: Pubkey, hash: Hash, nonce: u64) -> Instruction data: [ OreInstruction::Mine.to_vec(), MineArgs { - hash, nonce: nonce.to_le_bytes(), } .to_bytes() diff --git a/src/processor/mine.rs b/src/processor/mine.rs index f318e19..d7ee705 100644 --- a/src/processor/mine.rs +++ b/src/processor/mine.rs @@ -4,10 +4,9 @@ use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, - keccak::{hashv, Hash as KeccakHash, HASH_BYTES}, + keccak::{hashv, Hash as KeccakHash}, program::set_return_data, program_error::ProgramError, - program_memory::sol_memcmp, pubkey::Pubkey, slot_hashes::SlotHash, sysvar::{self, Sysvar}, @@ -70,8 +69,7 @@ pub fn process_mine<'a, 'info>( // Validate provided hash let mut proof_data = proof_info.data.borrow_mut(); let proof = Proof::try_from_bytes_mut(&mut proof_data)?; - validate_hash( - args.hash.into(), + let hash = validate_hash( proof.hash.into(), *signer.key, u64::from_le_bytes(args.nonce), @@ -89,7 +87,7 @@ pub fn process_mine<'a, 'info>( // Hash recent slot hash into the next challenge to prevent pre-mining attacks proof.hash = hashv(&[ - KeccakHash::from(args.hash).as_ref(), + hash.as_ref(), &slot_hashes_info.data.borrow()[0..size_of::()], ]) .into(); @@ -107,34 +105,26 @@ pub fn process_mine<'a, 'info>( /// Validates the provided hash, ensursing it is equal to SHA3(current_hash, singer, nonce). /// Fails if the provided hash is valid but does not satisfy the required difficulty. pub(crate) fn validate_hash( - hash: KeccakHash, current_hash: KeccakHash, signer: Pubkey, nonce: u64, difficulty: KeccakHash, -) -> Result<(), ProgramError> { - // Validate hash correctness - let hash_ = hashv(&[ +) -> Result { + let hash = hashv(&[ + nonce.to_le_bytes().as_slice(), current_hash.as_ref(), signer.as_ref(), - nonce.to_le_bytes().as_slice(), ]); - if sol_memcmp(hash.as_ref(), hash_.as_ref(), HASH_BYTES) != 0 { - return Err(OreError::HashInvalid.into()); - } - - // Validate hash difficulty if hash.gt(&difficulty) { return Err(OreError::DifficultyNotSatisfied.into()); } - - Ok(()) + Ok(hash) } #[cfg(test)] mod tests { use solana_program::{ - keccak::{hashv, Hash, HASH_BYTES}, + keccak::{Hash, HASH_BYTES}, pubkey::Pubkey, }; @@ -146,38 +136,17 @@ mod tests { let signer = Pubkey::new_unique(); let nonce = 10u64; let difficulty = Hash::new_from_array([255; HASH_BYTES]); - let h2 = hashv(&[ - h1.to_bytes().as_slice(), - signer.to_bytes().as_slice(), - nonce.to_le_bytes().as_slice(), - ]); - let res = validate_hash(h2, h1, signer, nonce, difficulty); + let res = validate_hash(h1, signer, nonce, difficulty); assert!(res.is_ok()); } #[test] fn test_validate_hash_fail() { - let h1 = Hash::new_from_array([1; HASH_BYTES]); - let signer = Pubkey::new_unique(); - let nonce = 10u64; - let difficulty = Hash::new_from_array([255; HASH_BYTES]); - let h2 = Hash::new_from_array([2; HASH_BYTES]); - let res = validate_hash(h2, h1, signer, nonce, difficulty); - assert!(res.is_err()); - } - - #[test] - fn test_validate_hash_fail_difficulty() { let h1 = Hash::new_from_array([1; HASH_BYTES]); let signer = Pubkey::new_unique(); let nonce = 10u64; let difficulty = Hash::new_from_array([0; HASH_BYTES]); - let h2 = hashv(&[ - h1.to_bytes().as_slice(), - signer.to_bytes().as_slice(), - nonce.to_le_bytes().as_slice(), - ]); - let res = validate_hash(h2, h1, signer, nonce, difficulty); + let res = validate_hash(h1, signer, nonce, difficulty); assert!(res.is_err()); } } diff --git a/tests/test_mine.rs b/tests/test_mine.rs index 727eb2a..04faf3d 100644 --- a/tests/test_mine.rs +++ b/tests/test_mine.rs @@ -62,7 +62,7 @@ async fn test_mine() { ); // Submit mine tx - let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], next_hash.into(), nonce); + let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); let res = banks.process_transaction(tx).await; assert!(res.is_ok()); @@ -161,7 +161,7 @@ async fn test_mine_alt_proof() { // Submit mine tx with invalid proof let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); - let (next_hash, nonce) = find_next_hash( + let (_next_hash, nonce) = find_next_hash( proof.hash.into(), KeccakHash::new_from_array([u8::MAX; 32]), payer.pubkey(), @@ -178,7 +178,6 @@ async fn test_mine_alt_proof() { data: [ OreInstruction::Mine.to_vec(), MineArgs { - hash: next_hash.into(), nonce: nonce.to_le_bytes(), } .to_bytes() @@ -213,7 +212,7 @@ async fn test_mine_correct_hash_alt_proof() { // Submit with correct hash for invalid proof let proof_alt_account = banks.get_account(proof_alt_pda.0).await.unwrap().unwrap(); let proof_alt = Proof::try_from_bytes(&proof_alt_account.data).unwrap(); - let (next_hash, nonce) = find_next_hash( + let (_next_hash, nonce) = find_next_hash( proof_alt.hash.into(), KeccakHash::new_from_array([u8::MAX; 32]), payer_alt.pubkey(), @@ -230,7 +229,6 @@ async fn test_mine_correct_hash_alt_proof() { data: [ OreInstruction::Mine.to_vec(), MineArgs { - hash: next_hash.into(), nonce: nonce.to_le_bytes(), } .to_bytes() @@ -258,14 +256,14 @@ async fn test_mine_bus_rewards_insufficient() { // Find next hash let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); - let (next_hash, nonce) = find_next_hash( + let (_next_hash, nonce) = find_next_hash( proof.hash.into(), KeccakHash::new_from_array([u8::MAX; 32]), payer.pubkey(), ); // Submit mine tx - let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], next_hash.into(), nonce); + let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); let res = banks.process_transaction(tx).await; assert!(res.is_err()); @@ -348,14 +346,14 @@ async fn test_mine_not_enough_accounts() { // Find next hash let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); - let (next_hash, nonce) = find_next_hash( + let (_next_hash, nonce) = find_next_hash( proof.hash.into(), KeccakHash::new_from_array([u8::MAX; 32]), payer.pubkey(), ); // Submit mine tx - let mut ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], next_hash.into(), nonce); + let mut ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); ix.accounts.remove(1); let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); let res = banks.process_transaction(tx).await; @@ -377,14 +375,14 @@ async fn test_mine_too_early() { // Find next hash let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); - let (next_hash, nonce) = find_next_hash( + let (_next_hash, nonce) = find_next_hash( proof.hash.into(), KeccakHash::new_from_array([u8::MAX; 32]), payer.pubkey(), ); // Submit mine tx - let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], next_hash.into(), nonce); + let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); let res = banks.process_transaction(tx).await; assert!(res.is_err()); @@ -406,14 +404,14 @@ async fn test_mine_needs_reset() { // Find next hash let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); - let (next_hash, nonce) = find_next_hash( + let (_next_hash, nonce) = find_next_hash( proof.hash.into(), KeccakHash::new_from_array([u8::MAX; 32]), payer.pubkey(), ); // Submit mine tx - let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], next_hash.into(), nonce); + let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); let res = banks.process_transaction(tx).await; assert!(res.is_err()); @@ -469,7 +467,7 @@ async fn test_mine_fail_bad_data() { // Shared variables for tests. let mut rng = rand::thread_rng(); - let (next_hash, nonce) = find_next_hash( + let (_next_hash, nonce) = find_next_hash( proof.hash.into(), KeccakHash::new_from_array([u8::MAX; 32]), payer.pubkey(), @@ -501,7 +499,6 @@ async fn test_mine_fail_bad_data() { // Fuzz test random hashes and nonces for _ in 0..FUZZ { - let next_hash = KeccakHash::new_unique(); let nonce: u64 = rng.gen(); assert_mine_tx_err( &mut banks, @@ -512,7 +509,6 @@ async fn test_mine_fail_bad_data() { proof_address, TREASURY_ADDRESS, sysvar::slot_hashes::id(), - next_hash, nonce, ) .await; @@ -529,7 +525,6 @@ async fn test_mine_fail_bad_data() { proof_address, TREASURY_ADDRESS, sysvar::slot_hashes::id(), - next_hash, nonce, ) .await; @@ -546,7 +541,6 @@ async fn test_mine_fail_bad_data() { Pubkey::new_unique(), TREASURY_ADDRESS, sysvar::slot_hashes::id(), - next_hash, nonce, ) .await; @@ -562,7 +556,6 @@ async fn test_mine_fail_bad_data() { TREASURY_ADDRESS, proof_address, sysvar::slot_hashes::id(), - next_hash, nonce, ) .await; @@ -577,7 +570,6 @@ async fn test_mine_fail_bad_data() { proof_address, TREASURY_ADDRESS, sysvar::clock::id(), - next_hash, nonce, ) .await; @@ -592,7 +584,6 @@ async fn assert_mine_tx_err( proof: Pubkey, treasury: Pubkey, slot_hash: Pubkey, - next_hash: KeccakHash, nonce: u64, ) { let ix = Instruction { @@ -607,7 +598,6 @@ async fn assert_mine_tx_err( data: [ OreInstruction::Mine.to_vec(), MineArgs { - hash: next_hash.into(), nonce: nonce.to_le_bytes(), } .to_bytes()