diff --git a/.gitignore b/.gitignore index 03b2709..1de5659 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -btc_mine_simulator/target/ +target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..056bfda --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,198 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "btc_mine_simulator" +version = "0.1.0" +dependencies = [ + "secp256k1", + "serde", + "serde_json", + "sha2", +] + +[[package]] +name = "cc" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "secp256k1" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/btc_mine_simulator/Cargo.toml b/Cargo.toml similarity index 87% rename from btc_mine_simulator/Cargo.toml rename to Cargo.toml index eca64dc..c79a9c8 100644 --- a/btc_mine_simulator/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,6 @@ edition = "2021" [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +secp256k1 = "0.29.0" +sha2 = "0.10.8" + diff --git a/btc_mine_simulator/.gitignore b/btc_mine_simulator/.gitignore deleted file mode 100644 index 1de5659..0000000 --- a/btc_mine_simulator/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target \ No newline at end of file diff --git a/btc_mine_simulator/Cargo.lock b/btc_mine_simulator/Cargo.lock deleted file mode 100644 index 250d632..0000000 --- a/btc_mine_simulator/Cargo.lock +++ /dev/null @@ -1,89 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "btc_mine_simulator" -version = "0.1.0" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "proc-macro2" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "serde" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "syn" -version = "2.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/btc_mine_simulator/src/main.rs b/btc_mine_simulator/src/main.rs deleted file mode 100644 index 883e70f..0000000 --- a/btc_mine_simulator/src/main.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::fs; -use std::io; -use std::path::Path; - -mod tx; -mod validate; -use tx::Transaction; -use validate::validate_transaction; - -fn read_transactions_from_dir(dir: &Path) -> io::Result<(Vec, usize, usize)> { - let mut transactions = Vec::new(); - let mut total_files = 0; - let mut failed_parses = 0; - - for entry in fs::read_dir(dir)? { - let entry = entry?; - let path = entry.path(); - if path.is_file() { - total_files += 1; - match fs::read_to_string(&path) { - Ok(data) => { - match serde_json::from_str::(&data) { - Ok(transaction) => transactions.push(transaction), - Err(e) => { // Capture the parse error - failed_parses += 1; - println!("Failed to parse file: {:?}, Reason: {}", path.display(), e); - // Prints out the specific reason for the parse failure - }, - } - }, - Err(e) => { // Capture the file read error - println!("Failed to read file: {:?}, Reason: {}", path.display(), e); - // This case handles file read errors - } - } - } - } - for tx in &transactions { - // println!("{:?}", tx.locktime); - if tx.locktime != 0 { - println!("wow {:?}", tx.locktime); - } - } - - println!("Total files processed: {}", total_files); - println!("Failed to parse: {}", failed_parses); - Ok((transactions, total_files, failed_parses)) -} - -fn main() { - let dir = Path::new("../mempool"); - let txs = match read_transactions_from_dir(dir) { - Ok((transactions, total_files, failed_parses)) => { - println!("Successfully parsed transactions: {}", transactions.len()); - println!("Total files: {}", total_files); - println!("Failed parses: {}", failed_parses); - transactions - }, - Err(e) => panic!("Error reading transactions: {}", e), - }; - let mut res = 0; - for tx in &txs { - if let Err(e) = validate_transaction(tx) { - println!("{:?}", tx.); - res += 1; - println!("error: {:?}", e); - - } - - } - println!("{:?}", res); - -} diff --git a/btc_mine_simulator/src/tx.rs b/btc_mine_simulator/src/tx.rs deleted file mode 100644 index d4d1f8b..0000000 --- a/btc_mine_simulator/src/tx.rs +++ /dev/null @@ -1,40 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug)] -pub struct Transaction { - pub version: i32, - pub locktime: u32, - pub vin: Vec, - pub vout: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct Input { - pub txid: String, - pub vout: u32, - pub prevout: PrevOut, - pub scriptsig: String, - pub scriptsig_asm: String, - pub witness: Option>, - pub is_coinbase: bool, - pub sequence: u32, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct PrevOut { - pub scriptpubkey: String, - pub scriptpubkey_asm: String, - pub scriptpubkey_type: String, - pub scriptpubkey_address: String, - pub value: u64, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct Output { - pub scriptpubkey: String, - pub scriptpubkey_asm: String, - pub scriptpubkey_type: String, - pub scriptpubkey_address: Option, - pub value: u64, -} - diff --git a/btc_mine_simulator/src/validate.rs b/btc_mine_simulator/src/validate.rs deleted file mode 100644 index e918d7d..0000000 --- a/btc_mine_simulator/src/validate.rs +++ /dev/null @@ -1,44 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::tx::Transaction; - -// Assuming the structs Transaction, Input, Output, PrevOut are defined as above - -pub fn validate_transaction(tx: &Transaction) -> Result<(), String> { - if tx.version < 1 || tx.version > 2 { - return Err("Unsupported transaction version".to_string()); - } - - if tx.vin.is_empty() { - return Err("Transaction has no inputs".to_string()); - } - - if tx.vout.is_empty() { - return Err("Transaction has no outputs".to_string()); - } - - for input in &tx.vin { - if input.is_coinbase && tx.vin.len() > 1 { - return Err("Coinbase transaction has more than one input".to_string()); - } - - if !input.is_coinbase && input.txid.is_empty() { - return Err("Input txid is empty".to_string()); - } - - if let Some(witness) = &input.witness { - if witness.is_empty() { - return Err("Witness is present but empty".to_string()); - } - } - } - - // let total_output_value: u64 = tx.vout.iter().map(|output| output.value).sum(); - // if total_output_value == 0 { - // return Err("Total output value is 0".to_string()); - // } - - // Further checks can include scriptsig and scriptpubkey validation, which are complex and require executing the scripts - - Ok(()) -} diff --git a/output.txt b/output.txt new file mode 100644 index 0000000..9681ea3 --- /dev/null +++ b/output.txt @@ -0,0 +1,103 @@ +BlockHeader { version: 1, previous_block_hash: "", merkle_root: "", time: 0, bits: 0, nonce: 35022 } +{"version":1,"locktime":0,"vin":[{"txid":"","vout":4294967295,"prevout":{"scriptpubkey":"","scriptpubkey_asm":"","scriptpubkey_type":"coinbase","scriptpubkey_address":"","value":0},"scriptsig":"arbitrary data","scriptsig_asm":"","witness":null,"is_coinbase":true,"sequence":4294967295}],"vout":[{"scriptpubkey":"miner's address or script","scriptpubkey_asm":"","scriptpubkey_type":"pay to script hash or pay to public key hash","scriptpubkey_address":"miner's address","value":6250616824}]} +fd6c51917e9dcef4b36f06a97c45fc012b32954c2606b29ea46fbf24627180b2 +f61ba1f5c008032ec0c6226935e41c0906e18768182253dabab18fb414977d79 +b03607c000e41a2c35c3d67f8410274428e02b9fc323b8c5d88013f5c36adaf2 +b69ebd3e9354c7197e66e8994b0d736bf72471952325ec48ae8fd99f234c7486 +c29f43f417fd8f7f4e6c49c9909ff05a21a7f860fe337aec08ab2210c3df0bca +c9ffefcac1150a79dca59e54218a4e2267987193210c3154c57e7e3c152e9f4f +5b6a68bcdeecc661d5e4762fbdd10bb2ab46850fa9a3e7fae8fc925797c30349 +e5dadb7cf200305d9a32270707f1e28792e7e59cafd412025a629d99d8fa8c74 +e8df4626764e473b45dc2f17cac9ccf1abcaefe14ace65c5a8b36dfe5bc1d52b +1da98f44f9799a7afd4f4733745403797a3ea9560a181e8bf35d33a7ec84f383 +921e498ba907d5821d47579619da62b42d4e73f1c5fcf5fe30b8c11a2196a8c8 +d21374704def04b718ef13b90597cc5eed31a85f2d5e38cdece8f3b067081195 +6ee77c8e124b843ceb7ccdb1988bb9808b39323c0aaf72585b1f849200044c31 +20668f91b715e308fdd8f6dba0027fa309b01651f54109f0541d8ee9763c260d +c9dc384fd54a9b7d9f9ee214be33d3dcf5b63ae7a959d30efbc5c805868ccb98 +ed4935165003a09098aea1296f11d4166ab5cf6e50d7489e0f82a08660f7cc8a +8989ed84ee8a37609e4b8aa16aa49ba8daf8885aea56f85d1672bb258e2fd1f2 +c58b9bbdad53334a763df2bd609e49a587c8cb7fb284424ce8543b878fdda8d1 +fc418b1aec8fa42583e87794f16e6c346bb660c51e46212a824e8bd0d79ac5de +9ab68801d474c278928d0dd11e0abccd3a8653b9b30a5185feb05a43e14283f2 +323e4f3ae31a1f934b7ba0494393402b0e9c6e040a57da9bdcce857402493717 +f29043c4e2144d4e6b71e728ca6f7cb3718f52e5bd40a438edcbc5e41255becd +de8e5af87d677bf5e4f1dfbe145f16fb922752cb3650986c125ac67d2171b722 +abedc0cfc2071f03c46265708132d267a4396cf77c5f99066c398b4aea711c90 +7999c95635436a2f6833fecb8f7bf9a700c1ef042cb9ded6317afbc1b0a0cb94 +233cb4f1be5aadc6ed2c9d5a3aca55fe790e1a77e6a7be736eb78da5e94cfc9d +1b9e7d37d4f2a5fdc38682d680e36502e4eb983d35bc7060ca871b66607958b3 +0ef0a023b634d42f6065d6fa6ffa65c59c0bf3fd80cd245dccf6491774f372a8 +a15ad6d104a37b8209ce7c054b8d985fc9254777f20e0fa9117e2f803da6f798 +1ff66ac7cce05dd73ba2b3dbc3efea124759582e643a53b6ff14e939b077b0bc +3bcde627e009d88f7c90e6a7c41a473c63df225b5b351b31572e9a3116164418 +1b8794ac391616ce39ee36d27ac2c7a0fa6f59c86d2770abf4787477b224c8a7 +5240468a06cff25050e66ea7eb29b9fb3a202a69c4a0aa29ed026ca395ae531a +8ea7bbecc3fdc9217f51d596056226f21558f31fdcf339aea72a3adcaa1a0354 +65de04a24879dd627414b942117eac52f9ce3e588357b7b48c9e2cceeaa10020 +1245a76885888a1f83996a310c5e8338cc213fdd00fef669d19846251a3dd9a9 +8bb9cc3fae73b5d6dedc305b24767fa5219bdfbf42a26682b174283dc532ee1f +88a33ef8a1fe8e5b8a0ab2d2bb92c43b8d328a34be4c7af85b1b371fe32ea05b +dd89640609e9d61132ea3fc31683b39d19aa6eefbe88ce6d7f6466a7475d9286 +5e1cb0b51d84b243ee144961e4d89e28ab1c2bcb74f9b8edf778f1b7ca9a0051 +3325fd0f39d2dbfcf1af7c189fcf8185204883dde64d48f35cc4ef280a9fed63 +1ad66f8eda77b2ceb26cb9e744a0c2db4ec49f7dab1d12fd7ddeb1048d1e8f94 +fd54b1a1b24e6bdd651dbf0cac4dbf0c66fad9863179277257ce5debe67baf2e +6550df27a673cc8a39d6e0525e742a9d3d51cec7b5839fcbd7bc3763464561a2 +0fc7e1dca82d1e5e09ccc1de37f8146bf9c71612fa7f8eb015594fb1976af7de +6b287dbfe2d4c8d82a570f7234981a62a476a257fe2f675228d513fe3b1171f7 +395d4b7d04db6ea40b9a9f227c6c8ea36797912dd988b4c3e2ecb16f89d4cd44 +e2adf87c5fe805e62645e6c95fa79f3955d17a68bc85422e07e484e5e7ead201 +f0d95f67d006510afe4f596a4d9a434d0d972857a989edd713af33dbe338cce5 +54f134f03552bb71aa8e29949710f8fa53f041838b20b041573f3ac077e1446b +394eba71a6c97104ba52a3e593a9de0ee72a8081cce0dc9ad15120cc0c54af22 +4ab31bba7fe1a0e49f319eb7456d560330680203116cc108cdd3a1adedcba2f6 +a72c35285d0b157ba1a10aefa54fb093658217daebfc6395896dd5263e116514 +ebcecdf8a1d9aab3e1c1aafc5b33336cfa8b5970f672c6494694447fe90630a9 +1a03612f53738cab1a31e84c934572b8e6521512231c97a2c56bf18dccb40624 +e2dbe2c3b1be040ccb1f2787165d59784cbb329e9d2751311f892a35a4832eae +da87057bfb3bb32c0c5a90c85cf329f82059134cd014259bfb6b2cd73aa32fd4 +b49d68458ebf1ef0d9f6361d5458d973e7c74eee74ce1f6a7135d52600b17444 +37fc115f78757a7878fd1c8b1a0096f515afb4ad2a6e3d64da1cfa4925b8bb6c +0b4e8ce425e7f1f4d93d0216cbdf0d036b9f29a759f6bd4dd1d0ed4798093bb4 +d6164d3110ce40e78244d11976b3238a24b19d6db4011bae7e1f58c83e5b555f +e466d26c4bf9c467f2d3d7f5f4e994e3ca3e7117a7e6c134b406e418f608c18f +6dd4d4439ff6ea50722e4f7309a0f3e60ddf361a483b5b7cac0e80b582ee484e +20ac37ddd19b6ab3412f24b480584ea59903bad3a9245466f1ad41f4921d68cf +dfb908de8bf20c672a2512038f5a681c056c50e4c17bc615ab0b4aef9e5b9efd +c90f1f60fec4b71dbf58355f91237c77a761b7a40be8ea8464fa732707058245 +cd83b145ba40b14843ff5fc816e106e3c744df0a01d9d1fd2f1bf33af61f6cf6 +ca4426c4d51b0b3a07518b3897836b0270b9fc5d33a1c56792e96dc2af4611cf +797328fde30e4868c95cf26c8d209d8ae9d1bc4b81ce5779bb63b4b2f37b87c4 +9a43a49242e9f0757afd059988b25d941da898625c703ede3a91e83b3da98def +c85e3a02297694ca971b5318c9e503bc18bc7aec8b2f1ed9c471e9356b330acb +82ac019ce9e671a02b5191afd8365d90e79dd9e5c93dfe9d94c311bc60c4023c +e347236eefec653d30e2d938d240289a867f5c247b8a9e52bfd36220668b2812 +42e9b2be6a03a0b67cb9df59824dc7afccdac0f99b8d68fbe5558aabcc0d6e5f +dd8df538a8d70e0928a4857ca07baeaee128dffe4f60cea0a0358261e946ef15 +a9abb01a4f6ba8c4132fdd15464400c71acd917656bfa5d18a669e06f959b437 +a59d7855abf3721e7dfab2473b76dfa7ddfca873bec1b681e7a1bd0311ca0f3a +9326485a16a912c7c78cc18caa8ca357f1305fbe98ce49e345e7ba063a008767 +9dec9675da7db73484e1b316a4b82c8f02b8988f59982b6261f31b6db2dfbbd6 +efdd8ab778aaaa50b80632815a28c44d8ca30349b76ae894cf892ee311c49175 +c1c533466cc4499c293c93350ed6809a8a9bd8bd10f3176327b7a9d8253d0773 +84c9e1abdacf151cf6848e25a9a8c568122fd6fa5e5d6f43e5583b585d2ccaac +2b8f5fb8ce910609fc6e5b72e58e1b7fa65e58c5eccdb67e4e038d2423ded6fd +f7f6cd7bef68c5b7887ee8b9ecc42dbba89d7483022dff7953aced44ddfbac2a +b297e1616f3f554bdde09c375498ab793d4587053fb9e8623a867cde9988a265 +827192f8870bb35a4319827778844666fee36c62d3db6cc4e74095ddde6bf0d3 +0b1f2f3f33f6a8c553236045d05eb17799299c25e95b625e2fd58b0b42fa2d4f +9bb6b6df0dcfa78c163fc9a32b8951d7d427bb9a32d00a923628ed7c5106c5dc +55145fa5bcf5ece7d038dab44bc7d50f77684be936de75ce5aed5c9a19c1923b +26efae64a334f0c1fe74cc069138bc5c25129e4469df0cb22a81076040674f67 +e1c9ed9226011da72fffa01c517d32b65dfc73d2583049a349222a1306cc87cf +7d5fb57fef2d28dc55bbddd6b6b6edd2faaefea7d2c510761b05d28ecc557eba +b9bf6b8785f569aaf5a7e77930f1b0da9124103808b30801a5a90f755010226d +bc05f09bc92b926b9e605178d1341fadbcdb8ce0766ea87bc4ea0a0c6b30eaee +5131a48061a1b95e208dca9bf03e457209c49e8bd0115c6cea1d5a41da79e3df +43763e32d64f917007033677bef1f7fe768421c48c5459635b11aff19c71fed4 +de3e74676f63474069deb4e3276eaf98e4ae9297ae2f451248f7a966c97cbe36 +d24484c3dc35542d2f4d4c862e61126b29f7563411608f399fd4ddc45f76b7e9 +492f69d73f2b16a00c516ae9fa1b27ae4f1c60681d96d1b5964c59c2122d9f3a +d7c9dc1d6ff72609f2d72c2842732f33201ca02968280c3b41b1c49cbb44b6e6 +83a4d16652052c9dee5e50200371960979ba379c29a181a51a13c80fdce449a2 diff --git a/run.sh b/run.sh index 721aeb2..ac1cdb7 100755 --- a/run.sh +++ b/run.sh @@ -1 +1,2 @@ -# Update this file to run your own code \ No newline at end of file +# Update this file to run your own code +cargo run \ No newline at end of file diff --git a/src/block.rs b/src/block.rs new file mode 100644 index 0000000..c1519fb --- /dev/null +++ b/src/block.rs @@ -0,0 +1,57 @@ +use serde::{Deserialize, Serialize}; +use serde_json; +use sha2::{Digest, Sha256}; +use std::{fs::File, io::Write, vec}; + +use crate::tx::Transaction; + +#[derive(Serialize, Deserialize, Debug)] +pub struct BlockHeader { + pub version: i32, + pub previous_block_hash: String, + pub merkle_root: String, + pub time: u32, + pub bits: u32, + pub nonce: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Block { + pub header: BlockHeader, + pub transactions: Vec, +} + +impl Block { + pub fn mine(&mut self, difficulty_target: &str) { + loop { + let header = serde_json::to_string(&self.header).unwrap(); + let hash = Sha256::digest(header.as_bytes()); + let hash_hex = format!("{:x}", hash); + + if hash_hex < difficulty_target.to_owned() { + println!("Block mined: {}", hash_hex); + break; + } + + self.header.nonce += 1; + } + } + + pub fn generate_output(&self) { + let mut output = File::create("output.txt").unwrap(); + + // Write block header + writeln!(output, "{:?}", self.header).unwrap(); + + // Serialize and write coinbase transaction + let coinbase_tx = serde_json::to_string(&self.transactions[0]).unwrap(); + writeln!(output, "{}", coinbase_tx).unwrap(); + + // Write transaction IDs + for tx in &self.transactions { + let tx_json = serde_json::to_string(tx).unwrap(); + let txid = Sha256::digest(tx_json.as_bytes()); + writeln!(output, "{:x}", txid).unwrap(); + } + } +} diff --git a/src/coinbase.rs b/src/coinbase.rs new file mode 100644 index 0000000..7689354 --- /dev/null +++ b/src/coinbase.rs @@ -0,0 +1,38 @@ +use crate::tx::{Input, Output, PrevOut, Transaction}; + +// Assume these are the calculated values +pub fn create_coinbase_transaction(block_reward: u64, total_fees: u64) -> Transaction { + // The output value of the coinbase transaction is the sum of block reward and total fees + let output_value = block_reward + total_fees; + + Transaction { + version: 1, // Version of the transaction format + locktime: 0, // Typically 0 for coinbase transactions + vin: vec![Input { + // Coinbase transactions have a single input + txid: String::new(), // No input transaction (empty string or all zeros) + vout: 0xffffffff, // Maximum value as it's not referencing a real output + prevout: PrevOut { + // Dummy prevout for coinbase tx + scriptpubkey: String::new(), // Could be used to include miner-specific data + scriptpubkey_asm: String::new(), + scriptpubkey_type: String::from("coinbase"), + scriptpubkey_address: String::new(), + value: 0, // No input value + }, + scriptsig: String::from("arbitrary data"), // Miners can include arbitrary data here + scriptsig_asm: String::new(), + witness: None, + is_coinbase: true, + sequence: 0xffffffff, // Full sequence + }], + vout: vec![Output { + // The output sending the reward to the miner's address + scriptpubkey: String::from("miner's address or script"), + scriptpubkey_asm: String::new(), + scriptpubkey_type: String::from("pay to script hash or pay to public key hash"), + scriptpubkey_address: Some(String::from("miner's address")), + value: output_value, + }], + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ce9abfb --- /dev/null +++ b/src/main.rs @@ -0,0 +1,111 @@ +use std::collections::HashSet; +use std::fs; +use std::io; +use std::path::Path; + +mod block; +mod coinbase; +mod tx; +mod validate; +use tx::Transaction; + +use crate::block::Block; +use crate::block::BlockHeader; +use crate::coinbase::create_coinbase_transaction; + +// use validate::validate_transaction; + +fn read_transactions_from_dir(dir: &Path) -> io::Result<(Vec, usize, usize)> { + let mut transactions = Vec::new(); + let mut total_files = 0; + let mut failed_parses = 0; + + for entry in fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_file() { + total_files += 1; + match fs::read_to_string(&path) { + Ok(data) => match serde_json::from_str::(&data) { + Ok(transaction) => transactions.push(transaction), + Err(_) => { + failed_parses += 1; + } + }, + Err(_) => {} + } + } + } + + Ok((transactions, total_files, failed_parses)) +} + +fn get_tx() -> Vec { + let dir = Path::new("./mempool"); + let txs = match read_transactions_from_dir(dir) { + Ok((transactions, total_files, failed_parses)) => { + println!("Successfully parsed transactions: {}", transactions.len()); + println!("Total files: {}", total_files); + println!("Failed parses: {}", failed_parses); + transactions + } + Err(e) => panic!("Error reading transactions: {}", e), + }; + + let mut invalid_transactions = 0; + let mut fail = 0; + let mut valid_txs = vec![]; + for tx in txs { + // if let Err(_) = validate_transaction(tx) { + // invalid_transactions += 1; + // } + if tx.is_basic_valid() { + valid_txs.push(tx); + } + } + valid_txs +} + +fn select_tx_for_block(txs: Vec) -> Vec { + // let mut res = vec!{}; + // for i in 0..100 { + // res.push(txs[i]); + // } + // res + txs[0..100].to_vec() +} + +fn main() { + let txs = get_tx(); + + let mut valid = select_tx_for_block(txs); + let total_fees = valid.iter().fold(0, |acc, x| acc + x.fee()); + + let br = 6_250_000_000; + let cb_tx = create_coinbase_transaction(br, total_fees); + let mut valid_tx = vec![cb_tx]; + valid_tx.append(&mut valid); + + let difficulty_target = "0000ffff00000000000000000000000000000000000000000000000000000000"; + + let mut block = Block { + header: BlockHeader { + version: 1, + previous_block_hash: "".to_string(), + merkle_root: "".to_string(), + time: 0, + bits: 0, + nonce: 0, + }, + transactions: valid_tx, + }; + + block.mine(difficulty_target); + block.generate_output(); + + // println!("Invalid transactions: {}", invalid_transactions); + // println!("Different script types found:"); + // for script_type in script_types { + // println!("- {}", script_type); + // } +} diff --git a/src/p2pkh.rs b/src/p2pkh.rs new file mode 100644 index 0000000..406e5a1 --- /dev/null +++ b/src/p2pkh.rs @@ -0,0 +1,3 @@ +fn validate() { + +} \ No newline at end of file diff --git a/src/tx.rs b/src/tx.rs new file mode 100644 index 0000000..a314240 --- /dev/null +++ b/src/tx.rs @@ -0,0 +1,75 @@ +use std::clone; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Transaction { + pub version: i32, + pub locktime: u32, + pub vin: Vec, + pub vout: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Input { + pub txid: String, + pub vout: u32, + pub prevout: PrevOut, + pub scriptsig: String, + pub scriptsig_asm: String, + pub witness: Option>, + pub is_coinbase: bool, + pub sequence: u32, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PrevOut { + pub scriptpubkey: String, + pub scriptpubkey_asm: String, + pub scriptpubkey_type: String, + pub scriptpubkey_address: String, + pub value: u64, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Output { + pub scriptpubkey: String, + pub scriptpubkey_asm: String, + pub scriptpubkey_type: String, + pub scriptpubkey_address: Option, + pub value: u64, +} + +impl Transaction { + pub fn is_basic_valid(&self) -> bool { + if self.vin.len() == 0 || self.vout.len() == 0 { + return false; + } + + let mut in_value = 0; + for input in &self.vin { + in_value += input.prevout.value; + } + let mut out_value = 0; + for output in &self.vout { + out_value += output.value; + } + if in_value < out_value { + return false; + } + + true + } + + pub fn fee(&self) -> u64 { + let mut in_value = 0; + for input in &self.vin { + in_value += input.prevout.value; + } + let mut out_value = 0; + for output in &self.vout { + out_value += output.value; + } + in_value - out_value + } +} diff --git a/src/validate.rs b/src/validate.rs new file mode 100644 index 0000000..dac059a --- /dev/null +++ b/src/validate.rs @@ -0,0 +1,71 @@ +// use crate::tx::Transaction; +// use secp256k1::{Message, PublicKey, Secp256k1, Signature}; +// use sha2::{Digest, Sha256}; + +// pub fn validate_transaction(tx: &Transaction) -> Result<(), String> { +// let secp = Secp256k1::verification_only(); + +// for (i, input) in tx.vin.iter().enumerate() { +// if input.is_coinbase { +// continue; +// } + +// // Validate the script type and extract the public key +// let prev_output = &input.prevout; +// let public_key = match prev_output.scriptpubkey_type.as_str() { +// "v1_p2tr" => { +// let pubkey_hex = &prev_output.scriptpubkey_asm[29..]; +// PublicKey::from_slice(&hex::decode(pubkey_hex).map_err(|_| "Invalid public key")?) +// .map_err(|_| "Invalid public key")? +// } +// _ => return Err("Unsupported script type".to_string()), +// }; + +// // Verify the signature +// let signature = Signature::from_der(&hex::decode(&input.witness.as_ref().unwrap()[0]).map_err(|_| "Invalid signature")?) +// .map_err(|_| "Invalid signature")?; + +// // Assuming the sighash type is `SIGHASH_ALL` +// let sighash_all: u32 = 1; + +// let mut sig_hash = Sha256::new(); +// sig_hash.update(&tx.version.to_le_bytes()); + +// for (j, input) in tx.vin.iter().enumerate() { +// if i == j { +// sig_hash.update(&hex::decode(&input.prevout.scriptpubkey).map_err(|_| "Invalid scriptpubkey")?); +// } else { +// sig_hash.update(&[0; 32]); +// sig_hash.update(&[0; 4]); +// } +// sig_hash.update(&input.sequence.to_le_bytes()); +// } + +// for output in &tx.vout { +// sig_hash.update(&output.value.to_le_bytes()); +// sig_hash.update(&hex::decode(&output.scriptpubkey).map_err(|_| "Invalid scriptpubkey")?); +// } + +// sig_hash.update(&tx.locktime.to_le_bytes()); +// sig_hash.update(&sighash_all.to_le_bytes()); + +// let message = Message::from_slice(&sig_hash.finalize()).map_err(|_| "Invalid message")?; +// secp.verify(&message, &signature, &public_key) +// .map_err(|_| "Signature verification failed")?; +// } + +// let total_output_value: u64 = tx.vout.iter().map(|output| output.value).sum(); + +// let mut total_input_value = 0; +// for input in &tx.vin { +// if !input.is_coinbase { +// total_input_value += input.prevout.value; +// } +// } + +// if total_output_value > total_input_value { +// return Err("Total output value exceeds total input value".to_string()); +// } + +// Ok(()) +// } diff --git a/btc_mine_simulator/todo b/todo similarity index 100% rename from btc_mine_simulator/todo rename to todo