Skip to content

Commit

Permalink
Trying to implement OP_CHECKSIG and other scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielgusn committed Apr 29, 2024
1 parent f7eedf6 commit 2876f44
Show file tree
Hide file tree
Showing 11 changed files with 791 additions and 41 deletions.
522 changes: 502 additions & 20 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ edition = "2021"
serde = { version = "1.0", features = ["derive"]}
chrono = "0.4.37"
hex-literal = "0.4.1"
ring = "0.17.8"
serde_json = "1.0.115"
sha2 = "0.10.8"
ripemd = "0.1.3"
merkletree = "0.23.0"
sha256 = "1.5.0"
hex = "0.4.3"
secp256k1 = "0.29.0"
signature = "2.2.0"
libsecp256k1 = "0.7.1"
1 change: 1 addition & 0 deletions output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f10eb050b1bf49d12cf34459ec07a7e0e4d0bbfe0fbb35a16385c1f26c889dd6
18 changes: 16 additions & 2 deletions src/block/block.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#![allow(dead_code, unused)]

use super::block_header::BlockHeader;
use crate::transactions::{self, tx::Tx};
use crate::{mempool::mempool::Mempool, transactions::{self, tx::Tx}};
use core::fmt;

const BLOCK_MAX_SIZE: u32 = 8000000;

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Block{
pub block_header: BlockHeader,
pub transactions: Vec<Tx>,
Expand All @@ -23,6 +23,20 @@ impl Block {
}
}

pub fn insert_transactions_from_mempool(&mut self, mempool: &mut Mempool) {
loop {
if mempool.txs.len() > 0{
if mempool.txs.last().unwrap().get_tx_size_in_bits() < self.get_block_size_left(){
self.push_transaction(mempool.txs.pop().unwrap());
println!("Txs Left on Mempool: {}", mempool.txs.len());
}
else {
break;
}
}
}
}

pub fn calculate_total_block_fee(&self) -> u64 {
let mut total_fee: u64 = 0;

Expand Down
59 changes: 45 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,61 @@ use block::block_header::BlockHeader;
use block::block::Block;
use chrono::Utc;
use utils::{read_mempool, read_tx_from_file};
use ring::digest::{Context, Digest, SHA256};
use std::fmt::Write;
use std::fs::File;
use std::io::prelude::*;
use mempool::mempool::Mempool;
use std::fs;

use crate::utils::validate_transaction_inputs;

fn main() {
// let file_size = fs::metadata("/home/gabriel/projects/bitcoin-mining-challenge/mempool/ff73248e38bfcdac87261f5a51f3143478937fda6b0d1def46e794b8f250e6dd.json").expect("Falha ao ler o arquivo");
// println!("Size: {} ", file_size.len());
let mut mempool: Mempool = read_mempool("/home/gabriel/projects/bitcoin-mining-challenge/mempool/");
mempool.sort_mempool_by_tx();

let first_block_header: BlockHeader = BlockHeader::new(String::from("00000000000000000000000000000000"), String::from("00000000000000000000000000000000"), Utc::now(), 128);
let mut block = Block::new(first_block_header, vec![]);
let genesis_block_header: BlockHeader = BlockHeader::new(String::from("00000000000000000000000000000000"), String::from("00000000000000000000000000000000"), Utc::now(), 128);
let mut genesis_block = Block::new(genesis_block_header.clone(), vec![]);

println!("{}", genesis_block.get_block_size());

let mut block_chain: Vec<Block> = vec![];

for tx in mempool.txs{
if tx.get_tx_size_in_bits() < block.get_block_size_left(){
block.push_transaction(tx);
}
else {
continue;
}
}

println!("{}", block);
println!("Mempool Size Before: {}", mempool.txs.len());

genesis_block.insert_transactions_from_mempool(&mut mempool);
block_chain.push(genesis_block.clone());
println!("Mempool Size After: {}", mempool.txs.len());
let tx = read_tx_from_file("/home/gabriel/projects/bitcoin-mining-challenge/mempool/0a8b21af1cfcc26774df1f513a72cd362a14f5a598ec39d915323078efb5a240.json");
// let tx = read_tx_from_file("/home/gabriel/projects/bitcoin-mining-challenge/mempool/0ac528562a1626863c0cb912eb725530c54e786e6485380c16633e4b9bce1720.json");

validate_transaction_inputs(&tx);

let mut file: File = File::create("output.txt").expect("Error while creating file");

file.write_all(genesis_block.block_header.get_block_header_sha256sum().as_bytes());
file.write_all(b"\n");

// while mempool.txs.len() > 6000 {
// let mut new_block_header: BlockHeader = BlockHeader::new(block_chain.last().unwrap().block_header.get_block_header_sha256sum(), String::from("00000000000000000000000000000000"), Utc::now(), 0);
// let mut new_block: Block = Block::new(new_block_header, vec![]);
// // if mempool.txs.last().unwrap().get_tx_size_in_bits() < new_block.get_block_size_left(){
// // new_block.push_transaction(mempool.txs.pop().unwrap());
// // println!("Txs Left on Mempool: {}", mempool.txs.len());
// // }
// // else {
// // break;
// // }
// println!("Inserting Txs on Block {}", new_block.block_header.block_id);
// new_block.insert_transactions_from_mempool(&mut mempool);
// block_chain.push(new_block);
// }

// println!("{}", block_chain.len());

// for block in block_chain{
// println!("{}", block);
// }

// println!("=================================");
// println!("{}", first_block_header);
Expand Down
1 change: 0 additions & 1 deletion src/mempool/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ impl Mempool{

pub fn sort_mempool_by_tx(&mut self) {
self.txs.sort_by(|a, b| a.get_tx_fee_per_bit().partial_cmp(&b.get_tx_fee_per_bit()).unwrap());
self.txs.reverse();
}

}
3 changes: 3 additions & 0 deletions src/script/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn OP_DUP() {

}
2 changes: 1 addition & 1 deletion src/transactions/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl Tx{

let result = hasher.finalize();

let hash_string = result.iter().map(|byte| format!("{:02x}", byte)).collect::<String>();
let hash_string: String = result.iter().map(|byte| format!("{:02x}", byte)).collect::<String>();

return hash_string;
}
Expand Down
157 changes: 155 additions & 2 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,167 @@
// use std::env;
#![allow(dead_code, unused)]

// use core::panicking::panic;
pub mod tree;

use crate::transactions::tx::{Tx, TxInput, TxOutput};
use crate::transactions::tx::{self, Tx, TxInput, TxOutput};
use crate::mempool::mempool::Mempool;
use serde_json;
use sha2::digest::core_api::TruncSide;
use sha2::{Sha256, Sha256VarCore};
use sha256::{digest, try_digest};
use std::path::Path;
use std::io::{self, Read};
use std::fs::{self, File};
use std::str::FromStr;
use std::thread::sleep;
use std::time;
use ripemd::{Ripemd160, Digest};
use hex;
use secp256k1::{Secp256k1, Message, SecretKey, PublicKey, ecdsa};
// use libsecp256k1::{Message, PublicKey, Signature, PublicKeyFormat};


pub fn get_merkle_root(tx_vec: &Vec<Tx>) -> String {
let merkle_root: String = String::new();

for tx in tx_vec{

}

String::new()
}

pub fn validate_transaction_inputs(tx: &Tx) -> Vec<String> {
let mut script: Vec<String> = vec![];
for vin in &tx.tx_input {
let mut scriptsig: Vec<String> = vec![];
scriptsig.extend(vin.scriptsig_asm.clone().split_whitespace().map(String::from));

let signature: String = scriptsig[1].clone();
let pubkey: String = scriptsig[3].clone();

script.push(signature);
script.push(pubkey);
script.extend(vin.prevout.scriptpubkey_asm.clone().split_whitespace().map(String::from));
}

let mut stack: Vec<String> = vec![];

println!("Starting the Script Stack");

for instruction in &script{
match instruction.as_str() {
"OP_DUP" => {
println!("OP_DUP de {}", stack.last().unwrap());
stack.push(stack.last().unwrap().clone());
println!("{:?}\n", stack);
}
"OP_HASH160" => {
let value: String = stack.pop().unwrap();

let mut value_hash = hash_160(&value);

println!("OP_HASH160 de {} virando {}", value, value_hash);

stack.push(value_hash);
println!("{:?}\n", stack);
}
"OP_EQUALVERIFY" => {
let last_stack_value = stack.pop().unwrap();
let pubkey = stack.pop().unwrap();
if last_stack_value != pubkey {
stack.push("OP_0".to_string());
}
}
"OP_CHECKSIG" => {
println!("{:?}", stack);

let secp = Secp256k1::new();

let pubkey_pop = stack.pop().unwrap();

// let pubkey_test = PublicKey::parse_slice(&hex::decode(&pubkey_pop).expect("Error while decoding pubkey to hex"), Some(PublicKeyFormat::Compressed)).expect("Error while parsing pubkey");

let pubkey_hex = hex::decode(pubkey_pop).expect("Error while decoding pubkey to hex");

let pubkey = PublicKey::from_slice(&pubkey_hex).expect("public keys must be 33 or 65 bytes, serialized according to SEC 2");

println!("{:?}", stack);

let signature = stack.pop().unwrap();

// println!("Signature {}", signature);
// println!("Signature len {}", &hex::decode(&signature).expect("Error while decoding signature to hex").len());

let mut signature_hex = hex::decode(&signature).expect("Error while decoding signature to hex");

signature_hex.remove(signature_hex.len() - 1);

// let sig_test = Signature::parse_der(&signature_hex).expect("Error while parsing signature");

// println!("sig_test {:?}", sig_test);

let signature = ecdsa::Signature::from_der(&signature_hex).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes");

println!("signature {}", signature);

let message_pop = tx.tx_input[0].txid.clone();

// println!("message_pop len {}", message_pop.len());

let mut message_hex = hex::decode(&message_pop).expect("Error while decoding message to hex");
// println!("message hex {:?}", message_hex);
// message_hex.reverse();
// println!("message hex {:?}", message_hex);

// println!("Address {}", hash_160(&pubkey_pop));

// let message_test = Message::parse_slice(&message_hex).expect("Error while parsing message");

let message = Message::from_digest_slice(&message_hex).expect("messages must be 32 bytes and are expected to be hashes");


// println!("tx op_checksig {}", libsecp256k1::verify(&message_test, &sig_test, &pubkey_test));
println!("{}", secp.verify_ecdsa(&message, &signature, &pubkey).unwrap_err());
// assert!();
}
instruction if instruction.starts_with("OP_PUSHBYTES_") => {
println!("Pushing bytes");
}
_ => {
println!("Inserindo item na lista");
stack.push(instruction.clone());
println!("{:?}\n", stack);
}
}
// sleep(time::Duration::from_secs(1));
}

script
}

pub fn hash_160(value: &String) -> String {

let hex_value = hex::decode(value).expect("Error while parsing hex from string");

let mut hasher256 = Sha256::new();

hasher256.update(hex_value);

let result_256 = hasher256.finalize();

let mut hasher_ripemd = Ripemd160::new();

hasher_ripemd.update(result_256);

let result_ripemd = hasher_ripemd.finalize();

let hash160_string: String = result_ripemd.clone().iter().map(|byte| format!("{:02x}", byte)).collect::<String>();

println!("\nHash RIPEMD160 de {} => {}\n", value, hash160_string);

hash160_string
}

pub fn read_mempool(path: &str) -> Mempool {

Expand Down
14 changes: 14 additions & 0 deletions src/utils/sha256.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use sha2::{Digest, Sha256, Sha256VarCore};

pub fn hash_sha256(value: String) -> String {

let bytes = value.as_bytes();

let mut hasher = Sha256::new();

hasher.update(bytes);

let result = hasher.finalize();

println!("{:?}", result);
}
47 changes: 47 additions & 0 deletions src/utils/tree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// use std::collections::VecDeque;

// #[derive(Debug, Clone)]
// pub struct TreeNode<T> {
// pub value: T,
// pub left: Option<Box<TreeNode<T>>>,
// pub right: Option<Box<TreeNode<T>>>,
// }

// impl<T> TreeNode<T>{
// pub fn new(value: T) -> Option<Box<TreeNode<T>>>{
// Some(Box::new(TreeNode {
// value,
// left: None,
// right: None,
// }))
// }
// }

// pub fn build_binary_tree_from_array<T>(array: Vec<Option<T>>) -> Option<Box<TreeNode<T>>> where T: Clone, {
// let mut root: Option<Box<TreeNode<T>>> = None;
// let mut queue: VecDeque<(Option<Box<TreeNode<T>>>, usize)> = VecDeque::new();

// if let Some(root_val) = array.get(0).cloned().flatten() {
// root = Some(Box::new(TreeNode::new(root_val.clone())));

// queue.push_back((root.as_mut().map(|r| r.as_mut()), 0));

// while let Some((mut node, index)) = queue.pop_front() {
// let left_index = 2 * index + 1;
// let right_index = 2 * index + 2;

// if let Some(left_val) = array.get(left_index).cloned().flatten() {
// let left_child: Option<Box<TreeNode<T>>> = Some(Box::new(TreeNode::new(left_val.clone())));
// node.as_mut().unwrap().left = left_child.clone();
// queue.push_back((left_child, left_index));
// }

// if let Some(right_val) = array.get(right_index).cloned().flatten() {
// let right_child: Option<Box<TreeNode<T>>> = Some(Box::new(TreeNode::new(right_val.clone())));
// node.as_mut().unwrap().right = right_child.clone();
// queue.push_back((right_child, right_index));
// }
// }

// }
// }

0 comments on commit 2876f44

Please sign in to comment.