From 27fed1e3307dd491fee1d3e35e0836dffc58ea03 Mon Sep 17 00:00:00 2001 From: Ian Slane Date: Fri, 27 Sep 2024 14:57:31 -0600 Subject: [PATCH] Refactor code with `cargo fmt` --- mine-your-first-block/.DS_Store | Bin 0 -> 6148 bytes mine-your-first-block/src/block.rs | 6 +- mine-your-first-block/src/main.rs | 31 +++-- mine-your-first-block/src/transactions.rs | 4 +- mine-your-first-block/src/utils.rs | 117 +++++++++-------- mine-your-first-block/src/validation.rs | 147 +++++++++++++--------- 6 files changed, 176 insertions(+), 129 deletions(-) create mode 100644 mine-your-first-block/.DS_Store diff --git a/mine-your-first-block/.DS_Store b/mine-your-first-block/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..19d1c91d80964b131d393e86a7898fda39a6cadf GIT binary patch literal 6148 zcmeHKJ5Iwu5S@VtS%M-Z73>vq0~48oIv0Qt6pBQSP-xL|368`8I06@-qM+l=&H!>^ zi7rCujkNn_=V$v#-rW%q9pBGJB0~|WFbvg{9x-#TYcGNaKrJ6Cv(|&|C6_imreh&ZJOz#ox)zdK0JQBA3dLK$IO0>S>68dbo!K0fKSf!VQa9hgcB0JLj#5$M)SSWXJ81G6JM z5cO1`r)snq>glkjh^qs$qo<2T^P%zNujWO|(@{T_aM9Y4GZ`QQT?Y1jIkfZt9KTF& zliy9@iVTo}f5w0gnn^RpN5$E?^?7#ICX7oA6N}5HK%jRn0a(~Ra$KD5Po^WT4$O{L S#q1>=$csQBgcBLq0Rx}YJu%Y& literal 0 HcmV?d00001 diff --git a/mine-your-first-block/src/block.rs b/mine-your-first-block/src/block.rs index 43a2bac..25d25c2 100644 --- a/mine-your-first-block/src/block.rs +++ b/mine-your-first-block/src/block.rs @@ -28,7 +28,7 @@ pub fn create_coinbase_tx(total_tx_fee: u64, witness_root_vec: Vec) -> T coinbase_tx.version = 0; // The txid variable is the witness data also - let txid= "0000000000000000000000000000000000000000000000000000000000000000".to_string(); + let txid = "0000000000000000000000000000000000000000000000000000000000000000".to_string(); // Initialize the input for the coinbase transaction coinbase_tx.vin.push(Vin { @@ -65,7 +65,7 @@ pub fn create_coinbase_tx(total_tx_fee: u64, witness_root_vec: Vec) -> T // Double hash the witness commitment, then format it for the scriptpubkey let wtxid_items_bytes = hex::decode(concant_items).unwrap(); - let wtxid_commitment_test = double_sha256(wtxid_items_bytes); + let wtxid_commitment_test = double_sha256(wtxid_items_bytes); let wtxid_commitment = hex::encode(wtxid_commitment_test); let scriptpubkey_for_wtxid_test = format!("6a24aa21a9ed{}", wtxid_commitment); @@ -88,7 +88,7 @@ pub fn construct_block_header(nonce: u32, merkle_root: String) -> BlockHeader { // The function takes a nonce and merkle root as input and returns a block header struct // Initialize the block header - let mut block_header = BlockHeader{ + let mut block_header = BlockHeader { version: 0x20000000, prev_block_hash: "".to_string(), merkle_root: merkle_root.to_string(), diff --git a/mine-your-first-block/src/main.rs b/mine-your-first-block/src/main.rs index 5831ba5..e1e2e18 100644 --- a/mine-your-first-block/src/main.rs +++ b/mine-your-first-block/src/main.rs @@ -1,12 +1,12 @@ +mod block; mod transactions; -mod validation; mod utils; -mod block; -use transactions::*; -use validation::*; -use utils::*; +mod validation; use block::*; use itertools::Itertools; +use transactions::*; +use utils::*; +use validation::*; /// The main driver function that mines the block fn main() { @@ -27,7 +27,8 @@ fn main() { let mut total_fees = 0u64; // Sort transactions by fee in descending order before processing - let sorted_valid_txs: Vec<_> = valid_txs.iter() + let sorted_valid_txs: Vec<_> = valid_txs + .iter() .sorted_by(|a, b| b.fee.cmp(&a.fee)) .collect(); @@ -35,7 +36,7 @@ fn main() { for tx in sorted_valid_txs { let tx_weight = calculate_transaction_weight(&tx.transaction); if total_weight + tx_weight > max_block_weight { - break; // Stop if adding this transaction would exceed the max block weight + break; // Stop if adding this transaction would exceed the max block weight } block_txs.push(tx.clone()); // Add the transaction to the block total_weight += tx_weight; // Add the weight to the total weight @@ -47,17 +48,18 @@ fn main() { // Get the wtxids for the witness root // Initialize the wtxids with the coinbase transaction - let mut wtx_ids_for_witness_root = vec!["0000000000000000000000000000000000000000000000000000000000000000".to_string()]; + let mut wtx_ids_for_witness_root = + vec!["0000000000000000000000000000000000000000000000000000000000000000".to_string()]; // Collect wtxids for witness root for tx in &block_txs { // If the transaction is p2wpkh, use the wtxid, otherwise use the txid if tx.is_p2wpkh { if let Some(ref wtxid) = tx.wtxid { - wtx_ids_for_witness_root.push(wtxid.clone()); // Collect wtxid if valid + wtx_ids_for_witness_root.push(wtxid.clone()); // Collect wtxid if valid } } else { - wtx_ids_for_witness_root.push(tx.txid.clone()); // Collect txid if not p2wpkh + wtx_ids_for_witness_root.push(tx.txid.clone()); // Collect txid if not p2wpkh } } @@ -85,7 +87,10 @@ fn main() { // Use block_txs to generate Merkle root // Txids_for_merkle is a vector of txids for the merkle root - let txids_for_merkle = block_txs.iter().map(|tx| tx.txid.clone()).collect::>(); + let txids_for_merkle = block_txs + .iter() + .map(|tx| tx.txid.clone()) + .collect::>(); let merkle_root = get_merkle_root(txids_for_merkle.clone()); // Start Mining! @@ -95,7 +100,7 @@ fn main() { let serialized_block_header = serialize_block_header(&block_header); // Calculate the hash of the block header - let block_hash = double_sha256(serialized_block_header.clone()); + let block_hash = double_sha256(serialized_block_header.clone()); let block_hash = reverse_bytes(block_hash.to_vec()); // Check if the hash meets the target @@ -108,4 +113,4 @@ fn main() { nonce += 1; } } -} \ No newline at end of file +} diff --git a/mine-your-first-block/src/transactions.rs b/mine-your-first-block/src/transactions.rs index bf3ead9..c79aa95 100644 --- a/mine-your-first-block/src/transactions.rs +++ b/mine-your-first-block/src/transactions.rs @@ -60,5 +60,5 @@ pub struct BlockHeader { pub merkle_root: String, pub timestamp: u32, pub bits: u32, - pub nonce: u32 -} \ No newline at end of file + pub nonce: u32, +} diff --git a/mine-your-first-block/src/utils.rs b/mine-your-first-block/src/utils.rs index 6577a66..08ff310 100644 --- a/mine-your-first-block/src/utils.rs +++ b/mine-your-first-block/src/utils.rs @@ -1,22 +1,21 @@ +use ripemd::Ripemd160; use serde_json; use sha2::{Digest as ShaDigest, Sha256}; use std::fs::File; -use std::io::{self, Write, BufReader}; -use ripemd::Ripemd160; use std::fs::OpenOptions; +use std::io::{self, BufReader, Write}; extern crate secp256k1; +use crate::transactions::{BlockHeader, Transaction, TransactionForProcessing}; +use byteorder::{LittleEndian, WriteBytesExt}; use std::error::Error; use std::fs; -use byteorder::{LittleEndian, WriteBytesExt}; -use crate::transactions::{BlockHeader, Transaction, TransactionForProcessing}; - /// This function calculates the merkle root. pub fn get_merkle_root(txids: Vec) -> String { - // This will iterate over each txid, decode from hex and reverse the byte order and collect // into a vector of 32 byte arrays for hashing - let mut be_txid = txids.iter() + let mut be_txid = txids + .iter() .map(|txid| { let decoded_id = hex::decode(txid).unwrap(); let reversed_id = decoded_id.iter().rev().cloned().collect::>(); @@ -34,15 +33,20 @@ pub fn get_merkle_root(txids: Vec) -> String { } // This will iterate over the txids (as bytes) in pairs of 2, concatenate them together and hash them - be_txid = be_txid.chunks(2) + be_txid = be_txid + .chunks(2) .map(|pair| { let mut hasher = Sha256::new(); hasher.update(pair[0]); hasher.update(pair[1]); let first_hash = hasher.finalize_reset().to_vec(); hasher.update(first_hash); - hasher.finalize().try_into().expect("Hash should be 32 bytes") - }).collect() + hasher + .finalize() + .try_into() + .expect("Hash should be 32 bytes") + }) + .collect() } // Return the merkle root as a hex string @@ -74,12 +78,22 @@ pub fn serialize_block_header(block_header: &BlockHeader) -> Vec { { let mut writer = &mut buffer[..]; // Write each field directly into the buffer at the correct position - writer.write_u32::(block_header.version).unwrap(); - writer.write_all(&hex::decode(&block_header.prev_block_hash).unwrap()).unwrap(); - writer.write_all(&hex::decode(&block_header.merkle_root).unwrap()).unwrap(); - writer.write_u32::(block_header.timestamp).unwrap(); + writer + .write_u32::(block_header.version) + .unwrap(); + writer + .write_all(&hex::decode(&block_header.prev_block_hash).unwrap()) + .unwrap(); + writer + .write_all(&hex::decode(&block_header.merkle_root).unwrap()) + .unwrap(); + writer + .write_u32::(block_header.timestamp) + .unwrap(); writer.write_u32::(block_header.bits).unwrap(); - writer.write_u32::(block_header.nonce).unwrap(); + writer + .write_u32::(block_header.nonce) + .unwrap(); } // Return the serialized block header @@ -102,7 +116,6 @@ pub fn serialize_tx(transaction: &Transaction) -> String { // Serialize txid for vin in &transaction.vin { - // Reverse the byte order of txid and push let txid_bytes = hex::decode(&vin.txid).unwrap(); let reversed_txid = reverse_bytes(txid_bytes); @@ -132,7 +145,6 @@ pub fn serialize_tx(transaction: &Transaction) -> String { // Now serialize vout count for vout in &transaction.vout { - // Next push the amount of sats little endian let value = &vout.value.to_le_bytes(); serialized_tx.push_str(&hex::encode(value)); @@ -180,7 +192,7 @@ pub fn serialized_segwit_tx(transaction: &Transaction) -> String { for vin in &transaction.vin { // Serialize txid and push let txid_bytes = hex::decode(&vin.txid).unwrap(); - let reversed_txid= reverse_bytes(txid_bytes); + let reversed_txid = reverse_bytes(txid_bytes); serialized_tx.push_str(&reversed_txid); // Serialize vout and push @@ -245,7 +257,6 @@ pub fn serialized_segwit_tx(transaction: &Transaction) -> String { serialized_tx } - /// This function will serialize a segwit wtransaction into a string of hex bytes pub fn serialized_segwit_wtx(transaction: &Transaction) -> String { let mut serialized_tx = String::new(); @@ -270,7 +281,6 @@ pub fn serialized_segwit_wtx(transaction: &Transaction) -> String { let reversed_txid = reverse_bytes(txid_bytes); serialized_tx.push_str(&reversed_txid); - // Serialize vout and push let vout = &vin.vout.to_le_bytes(); let vout_hex = hex::encode(vout); @@ -283,7 +293,6 @@ pub fn serialized_segwit_wtx(transaction: &Transaction) -> String { let sequence = &vin.sequence.to_le_bytes(); let sequence_hex = hex::encode(sequence); serialized_tx.push_str(&sequence_hex); - } // Push the vout count @@ -340,7 +349,6 @@ pub fn serialized_segwit_wtx(transaction: &Transaction) -> String { pub fn compact_size_as_bytes(size: usize) -> Vec { // Match the size of the bytes match size { - // If the size is less than 0xfd, return the size as a single byte 0..=0xfc => vec![size as u8], 0xfd..=0xffff => { @@ -348,26 +356,30 @@ pub fn compact_size_as_bytes(size: usize) -> Vec { let mut bytes = vec![0xfd]; bytes.extend_from_slice(&(size as u16).to_le_bytes()); bytes - }, + } // If the size is between 0x10000 and 0xffffffff, return the size as a 4-byte little-endian 0x10000..=0xffffffff => { let mut bytes = vec![0xfe]; bytes.extend_from_slice(&(size as u32).to_le_bytes()); bytes - }, + } // If the size is greater than 0xffffffff, return the size as an 8-byte little-endian _ => { let mut bytes = vec![0xff]; bytes.extend_from_slice(&(size as u64).to_le_bytes()); bytes - }, + } } } // File io operations /// This function constructs the block. It adds the header, coinbase tx and other txs to the output file -pub fn write_block_to_file(serialized_header: &[u8], serialized_cb_tx: &[u8], block_txs: &[TransactionForProcessing]) { - fs::write("../output.txt", "").unwrap(); // Clear the output file +pub fn write_block_to_file( + serialized_header: &[u8], + serialized_cb_tx: &[u8], + block_txs: &[TransactionForProcessing], +) { + fs::write("../output.txt", "").unwrap(); // Clear the output file // Append the serialized header and coinbase tx to the output file append_to_file("../output.txt", &hex::encode(serialized_header)).unwrap(); @@ -410,12 +422,14 @@ pub fn sha256(data: Vec) -> Vec { pub fn double_sha256(input: Vec) -> [u8; 32] { let first_hash = sha256(input); let second_hash = sha256(first_hash); - second_hash.try_into().expect("Expected a Vec of length 32") + second_hash + .try_into() + .expect("Expected a Vec of length 32") } /// This function will get the tx ready for signing by removing the scriptsig and adding the /// scriptpubkey to the scriptsig field and adding the sighash to the transaction -pub fn get_tx_readyfor_signing_legacy(transaction : &mut Transaction) -> Transaction { +pub fn get_tx_readyfor_signing_legacy(transaction: &mut Transaction) -> Transaction { // Get the signature and public key from the scriptsig let scriptsig = &transaction.vin[0].scriptsig; let (signature, _pubkey) = get_signature_and_publickey_from_scriptsig(scriptsig).unwrap(); @@ -427,7 +441,7 @@ pub fn get_tx_readyfor_signing_legacy(transaction : &mut Transaction) -> Transac } // Using the last two bytes of the signature as the sighash type for now - let sighash_type = &signature[signature.len()-2..]; + let sighash_type = &signature[signature.len() - 2..]; // Hard coding the sighash type for now let sighash = format!("{}000000", sighash_type); @@ -441,7 +455,7 @@ pub fn get_tx_readyfor_signing_legacy(transaction : &mut Transaction) -> Transac vin.scriptsig = String::new(); // Copy the scriptpubkey to the scriptsig field - vin.scriptsig = vin.prevout.scriptpubkey.clone(); + vin.scriptsig = vin.prevout.scriptpubkey.clone(); } // Return the tx @@ -459,7 +473,8 @@ pub fn get_segwit_tx_message( transaction: &mut Transaction, vin_index: usize, pubkey_hash: &str, - sighash_type: u8) -> Result> { + sighash_type: u8, +) -> Result> { let tx = transaction.clone(); // Serialize the version field of the tx little endian @@ -516,7 +531,7 @@ pub fn get_segwit_tx_message( // Sequence for input we sign let sequence = vin.sequence.to_le_bytes(); - let sequence= hex::encode(sequence); + let sequence = hex::encode(sequence); // Initialize the output hash let mut output_bytes = Vec::new(); @@ -553,17 +568,18 @@ pub fn get_segwit_tx_message( let formatted_sighash = hex::encode(sighash_type_u32.to_le_bytes()); // Preimage or message to be signed - let preimage = format!("{}{}{}{}{}{}{}{}{}{}", - version, - hex::encode(input_hash), - hex::encode(sequences_hash), - input, - scriptcode, - amount_le, - sequence, - hex::encode(output_hash), - locktime, - formatted_sighash, + let preimage = format!( + "{}{}{}{}{}{}{}{}{}{}", + version, + hex::encode(input_hash), + hex::encode(sequences_hash), + input, + scriptcode, + amount_le, + sequence, + hex::encode(output_hash), + locktime, + formatted_sighash, ); // Return the preimage @@ -571,7 +587,9 @@ pub fn get_segwit_tx_message( } /// This function gets the signature and public key from the scriptsig of a legacy transaction -pub fn get_signature_and_publickey_from_scriptsig(scriptsig: &str) -> Result<(String, String), Box> { +pub fn get_signature_and_publickey_from_scriptsig( + scriptsig: &str, +) -> Result<(String, String), Box> { // Convert the scriptsig hex string to bytes let scriptsig_bytes = hex::decode(scriptsig)?; @@ -582,7 +600,7 @@ pub fn get_signature_and_publickey_from_scriptsig(scriptsig: &str) -> Result<(St // Loop through the scriptsig bytes to parse while index < scriptsig_bytes.len() { // Check if the index is greater than the length of the scriptsig bytes - if index+1 >= scriptsig_bytes.len() { + if index + 1 >= scriptsig_bytes.len() { return Err("Unexpected end of scriptSig".into()); } @@ -595,8 +613,8 @@ pub fn get_signature_and_publickey_from_scriptsig(scriptsig: &str) -> Result<(St } // Get the data of the opcode length - let data = &scriptsig_bytes[index..index+length]; - index+=length; // Move the index to the next opcode + let data = &scriptsig_bytes[index..index + length]; + index += length; // Move the index to the next opcode // Push the data to the sig_and_pubkey_vec sig_and_pubkey_vec.push(hex::encode(data)); @@ -610,7 +628,6 @@ pub fn get_signature_and_publickey_from_scriptsig(scriptsig: &str) -> Result<(St Ok((sig_and_pubkey_vec[0].clone(), sig_and_pubkey_vec[1].clone())) } - /// This function will reverse the bytes and return a hex string pub fn reverse_bytes(mut bytes: Vec) -> String { bytes.reverse(); @@ -627,5 +644,5 @@ pub fn calculate_transaction_weight(tx: &Transaction) -> u64 { // Calculate weight of the transaction let tx_weight = base_size * 1.8 as u64 + total_size; - tx_weight // Return the weight of the transaction + tx_weight // Return the weight of the transaction } diff --git a/mine-your-first-block/src/validation.rs b/mine-your-first-block/src/validation.rs index 7300b30..50ab1ad 100644 --- a/mine-your-first-block/src/validation.rs +++ b/mine-your-first-block/src/validation.rs @@ -1,13 +1,17 @@ -use crate::transactions::{Transaction, TransactionForProcessing}; +use crate::transactions::{Transaction, TransactionForProcessing}; use std::io; use std::time::{SystemTime, UNIX_EPOCH}; extern crate secp256k1; -use secp256k1::{PublicKey, Secp256k1, Message}; +use crate::utils::{ + deserialize_tx, double_sha256, get_segwit_tx_message, + get_signature_and_publickey_from_scriptsig, get_tx_readyfor_signing_legacy, reverse_bytes, + ripemd160, serialize_tx, serialized_segwit_tx, serialized_segwit_wtx, sha256, +}; +use primitive_types::U256; +use secp256k1::ecdsa::Signature; +use secp256k1::{Message, PublicKey, Secp256k1}; use std::error::Error; use std::fs; -use secp256k1::ecdsa::Signature; -use primitive_types::U256; -use crate::utils::{deserialize_tx, double_sha256, get_segwit_tx_message, get_signature_and_publickey_from_scriptsig, get_tx_readyfor_signing_legacy, reverse_bytes, ripemd160, serialize_tx, serialized_segwit_tx, serialized_segwit_wtx, sha256}; /// This function will read through the mempool folder and validate the transactions before adding /// them to a transaction for processing vector @@ -40,21 +44,20 @@ pub fn process_mempool(mempool_path: &str) -> io::Result continue, } - }, + } "p2pkh" => { // If it's a p2pkh transaction validate it match p2pkh_script_validation(&mut transaction) { Ok((valid, tx_id)) if valid => { is_valid = true; txid = tx_id; - }, + } _ => continue, } - }, + } _ => continue, } @@ -72,7 +75,6 @@ pub fn process_mempool(mempool_path: &str) -> io::Result io::Result io::Result, pubkey: Vec, - serialized_tx: Vec) -> Result> { - + serialized_tx: Vec, +) -> Result> { // Removing the sighash type from the signature to get the actual signature - let signature = &signature[..signature.len()-1]; + let signature = &signature[..signature.len() - 1]; // Create a new Secp256k1 object let secp = Secp256k1::new(); @@ -116,26 +117,24 @@ pub fn verify_signature( let message_result = Message::from_digest_slice(&hash_array).unwrap(); // Create a public key from the pubkey - let public_key = PublicKey::from_slice(&pubkey).expect("Failed to create public key"); + let public_key = PublicKey::from_slice(&pubkey).expect("Failed to create public key"); // Create a signature from the der encoded signature let signature = Signature::from_der(&signature).unwrap(); // Verify the signature with the secp.verify_ecdsa function // Return Ok(true) if the signature is valid, Ok(false) if it's invalid - match secp.verify_ecdsa(&message_result, &signature, &public_key) { - Ok(_) => { - Ok(true) - }, - Err(_e) => { - Ok(false) - }, + match secp.verify_ecdsa(&message_result, &signature, &public_key) { + Ok(_) => Ok(true), + Err(_e) => Ok(false), } } // Transaction validation /// This function will validate P2WPKH transactions -pub fn p2wpkh_script_validation(transaction: &mut Transaction) -> Result<(bool, String, String), Box> { +pub fn p2wpkh_script_validation( + transaction: &mut Transaction, +) -> Result<(bool, String, String), Box> { // Create a stack to hold the data let mut stack: Vec> = Vec::new(); @@ -153,15 +152,15 @@ pub fn p2wpkh_script_validation(transaction: &mut Transaction) -> Result<(bool, // Get the signature index 0 let signature = hex::decode(witness[0].clone())?; - if signature.is_empty(){ + if signature.is_empty() { return Err("Signature is empty".into()); } // sighash type off sig - let sighash_type = signature[signature.len()-1]; + let sighash_type = signature[signature.len() - 1]; // Get the pubkey index 1 - let pubkey= hex::decode(witness[1].clone())?; + let pubkey = hex::decode(witness[1].clone())?; // Push the signature and pubkey onto the stack stack.push(signature); @@ -177,16 +176,19 @@ pub fn p2wpkh_script_validation(transaction: &mut Transaction) -> Result<(bool, &mut transaction.clone(), i, pubkey_hash, - sighash_type.clone() + sighash_type.clone(), )?; let message_in_bytes = hex::decode(&message_hash)?; // Now it execute like a p2pkh script - let script_pubkey_asm = format!("OP_DUP OP_HASH160 OP_PUSHBYTES_20 {} OP_EQUALVERIFY OP_CHECKSIG", pubkey_hash); + let script_pubkey_asm = format!( + "OP_DUP OP_HASH160 OP_PUSHBYTES_20 {} OP_EQUALVERIFY OP_CHECKSIG", + pubkey_hash + ); // Loop through the script_pubkey_asm // and execute the operations at each op code - for op in script_pubkey_asm.split_whitespace(){ + for op in script_pubkey_asm.split_whitespace() { match op { "OP_DUP" => { // If the stack is empty return false @@ -211,7 +213,9 @@ pub fn p2wpkh_script_validation(transaction: &mut Transaction) -> Result<(bool, "OP_EQUALVERIFY" => { // if stack is less than 2 return false if stack.len() < 2 { - return Err(format!("Stack underflow in OP_EQUALVERIFY for input {}", i).into()); + return Err( + format!("Stack underflow in OP_EQUALVERIFY for input {}", i).into() + ); } // Otherwise pop the last two items from the stack and compare them // if they are not equal return false, if they are just continue @@ -227,19 +231,24 @@ pub fn p2wpkh_script_validation(transaction: &mut Transaction) -> Result<(bool, "OP_CHECKSIG" => { // If the stack has less than two items return false if stack.len() < 2 { - return Err(format!("Stack underflow in OP_CHECKSIG for input {}", i).into()); + return Err( + format!("Stack underflow in OP_CHECKSIG for input {}", i).into() + ); } // otherwise pop the last two items from the stack (pubkey and signature) // and validate the signature let pubkey = stack.pop().unwrap(); let signature = stack.pop().unwrap(); - - match verify_signature(signature.clone(), pubkey.clone(), message_in_bytes.clone()) { + match verify_signature( + signature.clone(), + pubkey.clone(), + message_in_bytes.clone(), + ) { Ok(true) => { // If the signature is valid, push a 1 onto the stack stack.push(vec![1]); - }, + } Ok(false) => { // The signature verification was successful but reported the signature as invalid let pubkey_hex = hex::encode(&pubkey); @@ -248,13 +257,14 @@ pub fn p2wpkh_script_validation(transaction: &mut Transaction) -> Result<(bool, "Signature verification failed for input {}. The signature does not match the provided public key and message. PubKey: {}, Signature: {}", i, pubkey_hex, signature_hex ).into()); - }, + } Err(e) => { // An error occurred during the signature verification process return Err(format!( "An error occurred while verifying the signature for input {}: {}", i, e - ).into()); + ) + .into()); } } } @@ -288,14 +298,14 @@ pub fn p2wpkh_script_validation(transaction: &mut Transaction) -> Result<(bool, } /// This function will validate a P2PKH transaction -pub fn p2pkh_script_validation(transaction: &mut Transaction) -> Result<(bool, String), Box> { - +pub fn p2pkh_script_validation( + transaction: &mut Transaction, +) -> Result<(bool, String), Box> { // Create a stack to hold the data let mut stack: Vec> = Vec::new(); // Loop through the vin of the transaction - for (i,vin) in transaction.vin.iter().enumerate() { - + for (i, vin) in transaction.vin.iter().enumerate() { // Clearing the stack stack.clear(); @@ -304,8 +314,13 @@ pub fn p2pkh_script_validation(transaction: &mut Transaction) -> Result<(bool, S let script_pub_key = &vin.prevout.scriptpubkey_asm.clone(); // Get the signature and pubkey from the scriptsig - let (signature, pubkey) = get_signature_and_publickey_from_scriptsig(scriptsig) - .map_err(|e| format!("Error getting signature and public key from scriptsig for input {}: {}", i, e))?; + let (signature, pubkey) = + get_signature_and_publickey_from_scriptsig(scriptsig).map_err(|e| { + format!( + "Error getting signature and public key from scriptsig for input {}: {}", + i, e + ) + })?; // Prepare the transaction for signing let mut tx_for_signing = transaction.clone(); @@ -320,8 +335,10 @@ pub fn p2pkh_script_validation(transaction: &mut Transaction) -> Result<(bool, S .map_err(|_e| format!("Failed to decode the hex string for input: {}", i))?; // Push the signature and pubkey onto the stack - let decoded_signature = hex::decode(signature).map_err(|e| format!("Failed to decode signature: {}", e))?; - let decoded_pubkey = hex::decode(pubkey).map_err(|e| format!("Failed to decode pubkey: {}", e))?; + let decoded_signature = + hex::decode(signature).map_err(|e| format!("Failed to decode signature: {}", e))?; + let decoded_pubkey = + hex::decode(pubkey).map_err(|e| format!("Failed to decode pubkey: {}", e))?; stack.push(decoded_signature); stack.push(decoded_pubkey); @@ -351,7 +368,9 @@ pub fn p2pkh_script_validation(transaction: &mut Transaction) -> Result<(bool, S "OP_EQUALVERIFY" => { // if stack is less than 2 return false if stack.len() < 2 { - return Err(format!("Stack underflow in OP_EQUALVERIFY for input {}", i).into()); + return Err( + format!("Stack underflow in OP_EQUALVERIFY for input {}", i).into() + ); } // Otherwise pop the last two items from the stack and compare them // If they are not equal return false, if they are just continue @@ -367,19 +386,24 @@ pub fn p2pkh_script_validation(transaction: &mut Transaction) -> Result<(bool, S "OP_CHECKSIG" => { // If the stack has less than two items return false if stack.len() < 2 { - return Err(format!("Stack underflow in OP_CHECKSIG for input {}", i).into()); + return Err( + format!("Stack underflow in OP_CHECKSIG for input {}", i).into() + ); } // Otherwise pop the last two items from the stack (pubkey and signature) // and validate the signature let pubkey = stack.pop().unwrap(); let signature = stack.pop().unwrap(); - - match verify_signature(signature.clone(), pubkey.clone(), message_in_bytes.clone()) { + match verify_signature( + signature.clone(), + pubkey.clone(), + message_in_bytes.clone(), + ) { Ok(true) => { // If the signature is valid, push a 1 onto the stack stack.push(vec![1]); - }, + } Ok(false) => { // The signature verification was successful but reported the signature as invalid let pubkey_hex = hex::encode(&pubkey); @@ -388,13 +412,14 @@ pub fn p2pkh_script_validation(transaction: &mut Transaction) -> Result<(bool, S "Signature verification failed for input {}. The signature does not match the provided public key and message. PubKey: {}, Signature: {}", i, pubkey_hex, signature_hex ).into()); - }, + } Err(e) => { // An error occurred during the signature verification process return Err(format!( "An error occurred while verifying the signature for input {}: {}", i, e - ).into()); + ) + .into()); } } } @@ -421,26 +446,28 @@ pub fn p2pkh_script_validation(transaction: &mut Transaction) -> Result<(bool, S Ok((true, txid)) } - // Helper functions to weed out bad transactions. /// Function to get the tx amount so pub fn verify_tx_fee(transaction: &Transaction) -> u64 { // Calculate the total input amount - let total_input_amount: u64 = transaction.vin.iter() + let total_input_amount: u64 = transaction + .vin + .iter() .map(|input| input.prevout.value) .sum(); // Calculate the total output amount - let total_output_amount: u64 = transaction.vout.iter() - .map(|output| output.value) - .sum(); + let total_output_amount: u64 = transaction.vout.iter().map(|output| output.value).sum(); // Return the fee total_input_amount - total_output_amount } // Check double spend -pub fn check_double_spending(transaction: &Transaction, mempool: &Vec) -> bool { +pub fn check_double_spending( + transaction: &Transaction, + mempool: &Vec, +) -> bool { // Loop through mempool for tx in mempool { let tx = &tx.transaction; @@ -467,5 +494,3 @@ pub fn hash_meets_difficulty_target(hash: &str) -> bool { // Return true if the hash is less than the target hash_as_num < target } - -