Skip to content

Commit

Permalink
changed wtxid serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
slanesuke committed Apr 22, 2024
1 parent 9327108 commit 28137ea
Showing 1 changed file with 108 additions and 132 deletions.
240 changes: 108 additions & 132 deletions mine-your-first-block/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,6 @@ fn serialized_segwit_wtx(transaction: &Transaction) -> String {

for vin in &transaction.vin {
// Serialize txid and push
serialized_tx.push_str(&vin.txid);
// I believe the txid needs to be in reversed byte order
let txid_bytes = hex::decode(&vin.txid).unwrap();
let reversed_txid_bytes: Vec<u8> = txid_bytes.into_iter().rev().collect();
Expand All @@ -512,38 +511,8 @@ fn serialized_segwit_wtx(transaction: &Transaction) -> String {
let vout_hex = hex::encode(vout);
serialized_tx.push_str(&vout_hex);

// If its strictly a segwit tx, scriptsig field is empty so push zero
// if vin.scriptsig.is_empty() {
// serialized_tx.push_str("00");
// } else {
// // Otherwise it's a tx with both legacy and segwit inputs so I have to add the scriptsig
// // Coppied from the legacy serialize_tx function
// // Serialize scriptSig size I kept getting trailing zeros after my compactsize hex
// let scriptsig_size = vin.scriptsig.len() / 2;
//
// // So I had to do this to remove the trailing zeros
// // It basically converts the u64 to bytes then to a vec then removes the trailing zeros
// let mut scriptsig_size_bytes = (scriptsig_size as u64).to_le_bytes().to_vec();
//
// if let Some(last_non_zero_position) = scriptsig_size_bytes.iter().rposition(|&x| x != 0) {
// scriptsig_size_bytes.truncate(last_non_zero_position + 1);
// }
//
// let scriptsig_size_hex = hex::encode(&scriptsig_size_bytes);
// serialized_tx.push_str(&scriptsig_size_hex);
//
// // Now push scriptsig itself
// serialized_tx.push_str(&vin.scriptsig);
// }
if !vin.scriptsig.is_empty() {
let scriptsig_bytes = hex::decode(&vin.scriptsig).unwrap();
let scriptsig_size_bytes = compact_size_as_bytes(scriptsig_bytes.len());
serialized_tx.push_str(&hex::encode(&scriptsig_size_bytes));
serialized_tx.push_str(&vin.scriptsig);
} else {
// For SegWit inputs, scriptSig is empty
serialized_tx.push_str("00");
}
serialized_tx.push_str("00"); // `scriptSig` should always be empty for SegWit inputs.


let sequence = &vin.sequence.to_le_bytes();
let sequence_hex = hex::encode(sequence);
Expand Down Expand Up @@ -633,11 +602,6 @@ fn serialized_segwit_wtx(transaction: &Transaction) -> String {
let lock_hex = hex::encode(lock);
serialized_tx.push_str(&lock_hex);

// Unsure if segwit tx's need a sighash type so will keep it commented for now
// if transaction.sighash.is_some() {
// serialized_tx.push_str(&<std::option::Option<std::string::String> as Clone>::clone(&transaction.sighash).unwrap());
// }

serialized_tx
}

Expand Down Expand Up @@ -1367,103 +1331,115 @@ fn calculate_transaction_weight(tx: &Transaction) -> u64 {


fn main() {
// Path to the mempool folder
let mempool_path = "../mempool";

// Initialize nonce value;
let mut nonce = 0u32;

// Get the valid txs from the mempool
let valid_txs = process_mempool(mempool_path).unwrap();

// // Calculate the total fees and get the txids
// let mut valid_txids: Vec<String> = Vec::new();

// Initializing block weight
let mut block_txs: Vec<TransactionForProcessing> = Vec::new();
let mut total_weight = 0u64;
let max_block_weight = 4000000u64;
//let max_block_weight = 200000u64;
let mut total_fees = 0u64;

// Sort transactions by fee in descending order before processing
let sorted_valid_txs: Vec<_> = valid_txs.iter()
.sorted_by(|a, b| b.fee.cmp(&a.fee))
.collect();

// Select transactions to include in the block based on sorted order
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
}
block_txs.push(tx.clone());
total_weight += tx_weight;
total_fees += tx.fee;
}
let filename = "../mempool/0a768ce65115e0bf1b4fd4b3b1c5d1a66c56a9cc41d9fc1530a7ef3e4fdeaee7.json";
let deserialized_tx = deserialize_tx(filename);
let serde_wtx = serialized_segwit_wtx(&deserialized_tx);
println!("Serialized WTX: {}", serde_wtx);

// Sorting the transactions from fees in desencding order
block_txs.sort_by(|a, b| b.fee.cmp(&a.fee));
let mut get_wtxid = double_sha256(hex::decode(serde_wtx).unwrap());
println!("WTXID: {:?}", hex::encode(get_wtxid));
get_wtxid.reverse();
println!("WTXID reversed: {:?}", hex::encode(get_wtxid));

// Get the wtxids for the witness root
//let mut wtx_ids_for_witness_root = vec!["0000000000000000000000000000000000000000000000000000000000000000".to_string()];
let mut wtx_ids_for_witness_root: Vec<String> = Vec::new();
for tx in &block_txs {
if tx.is_p2wpkh {
if let Some(ref wtxid) = tx.wtxid {
wtx_ids_for_witness_root.push(wtxid.clone()); // Collect wtxid if valid
}
}
}


// Generate coinbase tx
let coinbase_tx = create_coinbase_tx(total_fees, wtx_ids_for_witness_root.clone());
let serialized_cb_tx = serialize_tx(&coinbase_tx);
let cd_tx_bytes = hex::decode(serialized_cb_tx.clone()).unwrap();
// coinbase txid
let coinbase_txid = double_sha256(cd_tx_bytes.clone());
let mut coinbase_txid_le = coinbase_txid.to_vec();
coinbase_txid_le.reverse();
let coinbase_txid = hex::encode(coinbase_txid_le);

// Insert the coinbase transaction at the beginning of block_txs
let coinbase_tx_for_processing = TransactionForProcessing {
transaction: coinbase_tx.clone(),
txid: coinbase_txid.clone(),
wtxid: Some("0000000000000000000000000000000000000000000000000000000000000000".to_string()),
fee: 0,
is_p2wpkh: false,
};
block_txs.insert(0, coinbase_tx_for_processing);

// Use block_txs to generate Merkle root
let txids_for_merkle = block_txs.iter().map(|tx| tx.txid.clone()).collect::<Vec<_>>();
let merkle_root = get_merkle_root(txids_for_merkle.clone());

// Start Mining!
loop {
// Get the block header and serialize it
let block_header = construct_block_header(nonce, merkle_root.clone());
let serialized_block_header = serialize_block_header(&block_header);

// Calculate the hash of the block header
//let block_hash = calculate_hash(serialized_block_header.clone());
let block_hash = double_sha256(serialized_block_header.clone());
let mut block_h = block_hash;
block_h.reverse();
let block_hash = hex::encode(block_h);

// Check if the hash meets the target
if hash_meets_difficulty_target(&block_hash) {
//write_block_to_file(&serialized_block_header, &cd_tx_bytes, &block_txs);
write_block_to_file(&serialized_block_header, &cd_tx_bytes, txids_for_merkle.clone(), &block_txs);
println!("Success, the block met the target difficulty!");
break;
} else {
nonce += 1;
}
}
// UNCOMMENT THIS TO MINE A BLOCK
// // Path to the mempool folder
// let mempool_path = "../mempool";
//
// // Initialize nonce value;
// let mut nonce = 0u32;
//
// // Get the valid txs from the mempool
// let valid_txs = process_mempool(mempool_path).unwrap();
//
// // // Calculate the total fees and get the txids
// // let mut valid_txids: Vec<String> = Vec::new();
//
// // Initializing block weight
// let mut block_txs: Vec<TransactionForProcessing> = Vec::new();
// let mut total_weight = 0u64;
// let max_block_weight = 4000000u64;
// //let max_block_weight = 200000u64;
// let mut total_fees = 0u64;
//
// // Sort transactions by fee in descending order before processing
// let sorted_valid_txs: Vec<_> = valid_txs.iter()
// .sorted_by(|a, b| b.fee.cmp(&a.fee))
// .collect();
//
// // Select transactions to include in the block based on sorted order
// 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
// }
// block_txs.push(tx.clone());
// total_weight += tx_weight;
// total_fees += tx.fee;
// }
//
// // Sorting the transactions from fees in desencding order
// block_txs.sort_by(|a, b| b.fee.cmp(&a.fee));
//
// // Get the wtxids for the witness root
// //let mut wtx_ids_for_witness_root = vec!["0000000000000000000000000000000000000000000000000000000000000000".to_string()];
// let mut wtx_ids_for_witness_root: Vec<String> = Vec::new();
// for tx in &block_txs {
// if tx.is_p2wpkh {
// if let Some(ref wtxid) = tx.wtxid {
// wtx_ids_for_witness_root.push(wtxid.clone()); // Collect wtxid if valid
// }
// }
// }
//
//
// // Generate coinbase tx
// let coinbase_tx = create_coinbase_tx(total_fees, wtx_ids_for_witness_root.clone());
// let serialized_cb_tx = serialize_tx(&coinbase_tx);
// let cd_tx_bytes = hex::decode(serialized_cb_tx.clone()).unwrap();
// // coinbase txid
// let coinbase_txid = double_sha256(cd_tx_bytes.clone());
// let mut coinbase_txid_le = coinbase_txid.to_vec();
// coinbase_txid_le.reverse();
// let coinbase_txid = hex::encode(coinbase_txid_le);
//
// // Insert the coinbase transaction at the beginning of block_txs
// let coinbase_tx_for_processing = TransactionForProcessing {
// transaction: coinbase_tx.clone(),
// txid: coinbase_txid.clone(),
// wtxid: Some("0000000000000000000000000000000000000000000000000000000000000000".to_string()),
// fee: 0,
// is_p2wpkh: false,
// };
// block_txs.insert(0, coinbase_tx_for_processing);
//
// // Use block_txs to generate Merkle root
// let txids_for_merkle = block_txs.iter().map(|tx| tx.txid.clone()).collect::<Vec<_>>();
// let merkle_root = get_merkle_root(txids_for_merkle.clone());
//
// // Start Mining!
// loop {
// // Get the block header and serialize it
// let block_header = construct_block_header(nonce, merkle_root.clone());
// let serialized_block_header = serialize_block_header(&block_header);
//
// // Calculate the hash of the block header
// //let block_hash = calculate_hash(serialized_block_header.clone());
// let block_hash = double_sha256(serialized_block_header.clone());
// let mut block_h = block_hash;
// block_h.reverse();
// let block_hash = hex::encode(block_h);
//
// // Check if the hash meets the target
// if hash_meets_difficulty_target(&block_hash) {
// //write_block_to_file(&serialized_block_header, &cd_tx_bytes, &block_txs);
// write_block_to_file(&serialized_block_header, &cd_tx_bytes, txids_for_merkle.clone(), &block_txs);
// println!("Success, the block met the target difficulty!");
// break;
// } else {
// nonce += 1;
// }
// }
}

fn write_block_to_file(serialized_header: &[u8], serialized_cb_tx: &[u8], txs: Vec<String>, block_txs: &[TransactionForProcessing]) {
Expand Down

0 comments on commit 28137ea

Please sign in to comment.