From 53ed95779247da3e10d5f16f92985aa418573196 Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Mon, 6 Oct 2025 00:55:23 +0200 Subject: [PATCH 1/9] feat: fetching block from mainnet --- goCode/goApp/main.go | 2 +- goCode/internal/config/config.go | 8 ++++---- goCode/internal/rpc/rpc.go | 3 ++- rustCode/src/config/mod.rs | 10 +++++++--- rustCode/src/lib.rs | 2 +- rustCode/src/main.rs | 21 +++++++++++++++------ rustCode/src/rpc/fetch.rs | 27 ++++++++++++++++++++++++--- 7 files changed, 54 insertions(+), 19 deletions(-) diff --git a/goCode/goApp/main.go b/goCode/goApp/main.go index 68a6414..33401a1 100644 --- a/goCode/goApp/main.go +++ b/goCode/goApp/main.go @@ -43,6 +43,6 @@ func main() { defer C.free(unsafe.Pointer(result)) goResult := C.GoString(result) - fmt.Println("Podaci o transakcijama iz poslednjeg bloka:\n", goResult) + fmt.Println("Rust FFI: Podaci o transakcijama iz poslednjeg bloka:\n", goResult) } diff --git a/goCode/internal/config/config.go b/goCode/internal/config/config.go index fa95c44..4ca9c03 100644 --- a/goCode/internal/config/config.go +++ b/goCode/internal/config/config.go @@ -13,9 +13,9 @@ func LoadEnv() (string, string, string) { log.Fatal("Greska pri ucitavanju .env fajla") } - rpcURL := os.Getenv("RPC_URL") - if rpcURL == "" { - log.Fatal("Nedostaje RPC_URL u .env fajlu") + rpcTestnetURL := os.Getenv("RPC_TESTNET_URL") + if rpcTestnetURL == "" { + log.Fatal("Nedostaje RPC_TESTNET_URL u .env fajlu") } recipient := os.Getenv("RECIPIENT_ADDRESS") @@ -28,5 +28,5 @@ func LoadEnv() (string, string, string) { log.Fatal("Nedostaje PRIVATE_KEY u .env fajlu") } - return rpcURL, recipient, privateKeyHex + return rpcTestnetURL, recipient, privateKeyHex } diff --git a/goCode/internal/rpc/rpc.go b/goCode/internal/rpc/rpc.go index 5ced86b..db89d3d 100644 --- a/goCode/internal/rpc/rpc.go +++ b/goCode/internal/rpc/rpc.go @@ -41,7 +41,8 @@ func GetLatestBlock(rpcURL string) string { log.Fatalf("Greska pri parsiranju JSON odgovora: %v", err) } - fmt.Println("BLOCK Odgovor:", string(rpcResp.Result)) + fmt.Println("sadrzaj BLOCK-a:\n", string(rpcResp.Result)) + fmt.Println() // Parsiramo blok var block Block diff --git a/rustCode/src/config/mod.rs b/rustCode/src/config/mod.rs index 3aa9669..284c19d 100644 --- a/rustCode/src/config/mod.rs +++ b/rustCode/src/config/mod.rs @@ -1,11 +1,15 @@ use dotenvy::from_path; use std::{env, path::Path}; -pub fn load_env() { +pub fn load_testnet_env() { let env_path = Path::new("../goCode/.env"); from_path(env_path).expect("Nije moguce ucitati .env fajl sa date putanje"); } -pub fn get_rpc_url() -> String { - env::var("RPC_URL").expect("RPC_URL nije definisan") +pub fn get_testnet_rpc_url() -> String { + env::var("RPC_TESTNET_URL").expect("RPC_URL nije definisan") } + +pub fn get_mainnet_rpc_url() -> String { + env::var("RPC_MAINNET_URL").expect("RPC_URL nije definisan") +} \ No newline at end of file diff --git a/rustCode/src/lib.rs b/rustCode/src/lib.rs index 12bfc2a..b32e637 100644 --- a/rustCode/src/lib.rs +++ b/rustCode/src/lib.rs @@ -13,7 +13,7 @@ pub extern "C" fn fetch_transactions(rpc_url: *const c_char) -> *mut c_char { // Pozivanje fetch_latest_block funkcije za dobijanje najnovijeg bloka let future = tokio::runtime::Runtime::new() .unwrap() - .block_on(fetch_latest_block(rpc_url_str)); + .block_on(fetch_latest_block(rpc_url_str, true)); // Prikupljanje transakcija iz rezultata let mut transaction_data = String::new(); diff --git a/rustCode/src/main.rs b/rustCode/src/main.rs index 70cfe9c..f405ede 100644 --- a/rustCode/src/main.rs +++ b/rustCode/src/main.rs @@ -2,9 +2,9 @@ mod config; mod models; mod rpc; -use config::{get_rpc_url, load_env}; +use config::{get_testnet_rpc_url, get_mainnet_rpc_url, load_testnet_env}; use models::SimpleBlock; -use rpc::fetch::fetch_latest_block; +use rpc::fetch::{fetch_latest_block, fetch_block_by_number}; use tokio; fn print_block_info(block: &SimpleBlock) { @@ -26,11 +26,20 @@ fn print_block_info(block: &SimpleBlock) { } #[tokio::main] -async fn main() { - load_env(); +async fn main() -> Result<(), Box> { + load_testnet_env(); - let rpc_url = get_rpc_url(); + let testnet_rpc_url = get_testnet_rpc_url(); - let block = fetch_latest_block(&rpc_url).await; + let block = fetch_latest_block(&testnet_rpc_url, true).await; print_block_info(&block); + + println!("----------------------"); + let mainnet_rpc_url = get_mainnet_rpc_url(); + println!("{}",mainnet_rpc_url); + + let block_response = fetch_block_by_number(&mainnet_rpc_url,"latest" , false).await?; + println!("{}",block_response); + + Ok(()) } diff --git a/rustCode/src/rpc/fetch.rs b/rustCode/src/rpc/fetch.rs index 1298f31..e9437a6 100644 --- a/rustCode/src/rpc/fetch.rs +++ b/rustCode/src/rpc/fetch.rs @@ -1,12 +1,12 @@ use crate::models::{RPCResponse, SimpleBlock}; use reqwest::Client; -use serde_json::json; +use serde_json::{json, Value}; -pub async fn fetch_latest_block(rpc_url: &str) -> SimpleBlock { +pub async fn fetch_latest_block(rpc_url: &str, transaction_bool: bool) -> SimpleBlock { let req_body = json!( { "jsonrpc": "2.0", "method": "eth_getBlockByNumber", - "params": ["latest", true], + "params": ["latest", transaction_bool], "id": 1 }); @@ -21,4 +21,25 @@ pub async fn fetch_latest_block(rpc_url: &str) -> SimpleBlock { let resp_json: RPCResponse = resp.json().await.expect("Greska pri parsiranju odgovora"); resp_json.result +} + +pub async fn fetch_block_by_number(rpc_url: &str, block_number: &str, transaction_bool: bool +) -> Result> { + let req_body = json!( { + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [block_number, transaction_bool], + "id": 1 + }); + + let client = Client::new(); + let resp = client + .post(rpc_url) + .json(&req_body) + .send() + .await?; + + let tekst=resp.text().await?; + + Ok(tekst) } \ No newline at end of file From 9e93d5ec42301d8280c582423df32c4584f68603 Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Tue, 7 Oct 2025 01:22:14 +0200 Subject: [PATCH 2/9] feat: find_max_gas_transaction + fetch_transaction_receipt --- rustCode/src/main.rs | 32 +++++++++++++++++++++++++++++--- rustCode/src/models/mod.rs | 27 ++++++++++++++++++++++++++- rustCode/src/rpc/fetch.rs | 35 +++++++++++++++++++++++++++++------ 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/rustCode/src/main.rs b/rustCode/src/main.rs index f405ede..b43db26 100644 --- a/rustCode/src/main.rs +++ b/rustCode/src/main.rs @@ -7,14 +7,20 @@ use models::SimpleBlock; use rpc::fetch::{fetch_latest_block, fetch_block_by_number}; use tokio; +use crate::{models::SimpleTransaction, rpc::fetch::fetch_transaction_receipt}; + fn print_block_info(block: &SimpleBlock) { println!("Blok broj: {}", block.number); println!("Hash bloka: {}", block.hash); println!("Timestamp: {}", block.timestamp); println!("Gas used: {}", block.gas_used); println!("Broj transakcija: {}", block.transactions.len()); + println!("Transakcije: "); + //print_transactions(&block.transactions); +} - for tx in &block.transactions { +fn print_transactions(transactions: &[SimpleTransaction]) { + for tx in transactions { println!("---"); println!("Tx hash: {}", tx.hash); println!("From: {}", tx.from); @@ -23,6 +29,15 @@ fn print_block_info(block: &SimpleBlock) { println!("Gas: {}", tx.gas); println!("Gas price: {}", tx.gas_price); } + + print!("----------------------"); + println!("ispisano je {} transakcija", transactions.len()); +} + +fn find_max_gas_transaction(transactions: &[SimpleTransaction]) -> Option<&SimpleTransaction> { + transactions + .iter() + .max_by_key(|tx| u64::from_str_radix(tx.gas.trim_start_matches("0x"), 16).unwrap_or(0)) } #[tokio::main] @@ -38,8 +53,19 @@ async fn main() -> Result<(), Box> { let mainnet_rpc_url = get_mainnet_rpc_url(); println!("{}",mainnet_rpc_url); - let block_response = fetch_block_by_number(&mainnet_rpc_url,"latest" , false).await?; - println!("{}",block_response); + let block_response = fetch_block_by_number(&mainnet_rpc_url,"latest" , true).await; + print_block_info(&block_response); + let transactions = block_response.transactions; + print_transactions(&transactions); + + println!("----------------------"); + + if let Some(max_tx) = find_max_gas_transaction(&transactions){ + println!("{:?}",max_tx); + let res = fetch_transaction_receipt(&mainnet_rpc_url, &max_tx.hash).await; + println!("{:?}", res); + } + Ok(()) } diff --git a/rustCode/src/models/mod.rs b/rustCode/src/models/mod.rs index f957c88..d978f43 100644 --- a/rustCode/src/models/mod.rs +++ b/rustCode/src/models/mod.rs @@ -1,7 +1,7 @@ use serde::Deserialize; #[derive(Debug, Deserialize)] -pub struct RPCResponse { +pub struct RPCResponseBlock { pub result: SimpleBlock, } @@ -26,3 +26,28 @@ pub struct SimpleTransaction { #[serde(rename = "gasPrice")] pub gas_price: String, } + +#[derive(Debug, Deserialize)] +pub struct RPCResponseBlockTransactions { + pub result: BlockTransactions, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BlockTransactions { + pub block_hash: String, + pub transactions: Vec, +} + +#[derive(Debug, Deserialize)] +pub struct RPCResponseReceipt { + pub result: TransactionReceipt, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionReceipt { + transaction_hash: String, + gas_used: String, + cumulative_gas_used: String, +} \ No newline at end of file diff --git a/rustCode/src/rpc/fetch.rs b/rustCode/src/rpc/fetch.rs index e9437a6..35a0d0c 100644 --- a/rustCode/src/rpc/fetch.rs +++ b/rustCode/src/rpc/fetch.rs @@ -1,4 +1,4 @@ -use crate::models::{RPCResponse, SimpleBlock}; +use crate::models::{BlockTransactions, RPCResponseBlock, RPCResponseBlockTransactions, RPCResponseReceipt, SimpleBlock, TransactionReceipt}; use reqwest::Client; use serde_json::{json, Value}; @@ -18,13 +18,13 @@ pub async fn fetch_latest_block(rpc_url: &str, transaction_bool: bool) -> Simple .await .expect("Greska pri slanju zahteva"); - let resp_json: RPCResponse = resp.json().await.expect("Greska pri parsiranju odgovora"); + let resp_json: RPCResponseBlock = resp.json().await.expect("Greska pri parsiranju odgovora"); resp_json.result } pub async fn fetch_block_by_number(rpc_url: &str, block_number: &str, transaction_bool: bool -) -> Result> { +) -> SimpleBlock { let req_body = json!( { "jsonrpc": "2.0", "method": "eth_getBlockByNumber", @@ -37,9 +37,32 @@ pub async fn fetch_block_by_number(rpc_url: &str, block_number: &str, transactio .post(rpc_url) .json(&req_body) .send() - .await?; + .await + .expect("Greska pri slanju zahteva"); - let tekst=resp.text().await?; + let resp_json: RPCResponseBlock = resp.json().await.expect("Greska pri parsiranju odgovora"); + + resp_json.result +} + +pub async fn fetch_transaction_receipt(rpc_url: &str, tx_hash: &str) -> TransactionReceipt { + let req_body = json!({ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": [tx_hash], + "id": 1 + }); + + let client = Client::new(); + + let resp = client + .post(rpc_url) + .json(&req_body) + .send() + .await + .expect("Greska pri slanju zahteva"); + + let receipt_resp: RPCResponseReceipt = resp.json().await.expect("Greska pri parsiranju odgovora"); - Ok(tekst) + receipt_resp.result } \ No newline at end of file From 3d5de83afab7fb76f215c28d8e1fae75b90cee68 Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Tue, 7 Oct 2025 02:18:40 +0200 Subject: [PATCH 3/9] feat: Add calculation of transaction gas used and its percentage of block gas used --- rustCode/src/main.rs | 24 ++++++++++++++++++++---- rustCode/src/models/mod.rs | 6 +++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/rustCode/src/main.rs b/rustCode/src/main.rs index b43db26..4341f53 100644 --- a/rustCode/src/main.rs +++ b/rustCode/src/main.rs @@ -30,7 +30,7 @@ fn print_transactions(transactions: &[SimpleTransaction]) { println!("Gas price: {}", tx.gas_price); } - print!("----------------------"); + println!("----------------------"); println!("ispisano je {} transakcija", transactions.len()); } @@ -61,9 +61,25 @@ async fn main() -> Result<(), Box> { println!("----------------------"); if let Some(max_tx) = find_max_gas_transaction(&transactions){ - println!("{:?}",max_tx); - let res = fetch_transaction_receipt(&mainnet_rpc_url, &max_tx.hash).await; - println!("{:?}", res); + println!("Transakcija sa najvecim gas limitom: "); + println!("Hash {}", max_tx.hash); + println!("Gas limit: (hex): {}", max_tx.gas); + + let receipt = fetch_transaction_receipt(&mainnet_rpc_url, &max_tx.hash).await; + //println!("{:?}", receipt); + + let tx_gas_used = + u64::from_str_radix(receipt.gas_used.trim_start_matches("0x"), 16).unwrap_or(0); + let block_gas_used = + u64::from_str_radix(block_response.gas_used.trim_start_matches("0x"), 16).unwrap_or(1); + + let percent_of_block = (tx_gas_used as f64 / block_gas_used as f64) * 100.0; + + println!("Gas potrosen od ove transakcije: {}", tx_gas_used); + println!("Gas potrosen u bloku: {}", block_gas_used); + println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block); + } else { + println!("Nema transakcija u ovom bloku"); } diff --git a/rustCode/src/models/mod.rs b/rustCode/src/models/mod.rs index d978f43..45062a8 100644 --- a/rustCode/src/models/mod.rs +++ b/rustCode/src/models/mod.rs @@ -47,7 +47,7 @@ pub struct RPCResponseReceipt { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionReceipt { - transaction_hash: String, - gas_used: String, - cumulative_gas_used: String, + pub transaction_hash: String, + pub gas_used: String, + pub cumulative_gas_used: String, } \ No newline at end of file From 2522d7d3f8df4ca9950dda8e45cf882baafab71f Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Tue, 7 Oct 2025 11:39:52 +0200 Subject: [PATCH 4/9] refactor: modularize --- rustCode/src/main.rs | 39 +++------------------------------------ rustCode/src/utils/mod.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 36 deletions(-) create mode 100644 rustCode/src/utils/mod.rs diff --git a/rustCode/src/main.rs b/rustCode/src/main.rs index 4341f53..49b227f 100644 --- a/rustCode/src/main.rs +++ b/rustCode/src/main.rs @@ -1,45 +1,13 @@ mod config; mod models; mod rpc; +mod utils; use config::{get_testnet_rpc_url, get_mainnet_rpc_url, load_testnet_env}; -use models::SimpleBlock; -use rpc::fetch::{fetch_latest_block, fetch_block_by_number}; +use rpc::fetch::{fetch_latest_block, fetch_block_by_number, fetch_transaction_receipt}; +use utils::{print_block_info, print_transactions, find_max_gas_transaction}; use tokio; -use crate::{models::SimpleTransaction, rpc::fetch::fetch_transaction_receipt}; - -fn print_block_info(block: &SimpleBlock) { - println!("Blok broj: {}", block.number); - println!("Hash bloka: {}", block.hash); - println!("Timestamp: {}", block.timestamp); - println!("Gas used: {}", block.gas_used); - println!("Broj transakcija: {}", block.transactions.len()); - println!("Transakcije: "); - //print_transactions(&block.transactions); -} - -fn print_transactions(transactions: &[SimpleTransaction]) { - for tx in transactions { - println!("---"); - println!("Tx hash: {}", tx.hash); - println!("From: {}", tx.from); - println!("To: {}", tx.to.clone().unwrap_or_else(|| "N/A".into())); - println!("Value: {}", tx.value); - println!("Gas: {}", tx.gas); - println!("Gas price: {}", tx.gas_price); - } - - println!("----------------------"); - println!("ispisano je {} transakcija", transactions.len()); -} - -fn find_max_gas_transaction(transactions: &[SimpleTransaction]) -> Option<&SimpleTransaction> { - transactions - .iter() - .max_by_key(|tx| u64::from_str_radix(tx.gas.trim_start_matches("0x"), 16).unwrap_or(0)) -} - #[tokio::main] async fn main() -> Result<(), Box> { load_testnet_env(); @@ -82,6 +50,5 @@ async fn main() -> Result<(), Box> { println!("Nema transakcija u ovom bloku"); } - Ok(()) } diff --git a/rustCode/src/utils/mod.rs b/rustCode/src/utils/mod.rs new file mode 100644 index 0000000..83aeeb6 --- /dev/null +++ b/rustCode/src/utils/mod.rs @@ -0,0 +1,30 @@ +use crate::models::{SimpleBlock, SimpleTransaction}; + +pub fn print_block_info(block: &SimpleBlock) { + println!("Blok broj: {}", block.number); + println!("Hash bloka: {}", block.hash); + println!("Timestamp: {}", block.timestamp); + println!("Gas used: {}", block.gas_used); + println!("Broj transakcija: {}", block.transactions.len()); +} + +pub fn print_transactions(transactions: &[SimpleTransaction]) { + for tx in transactions { + println!("---"); + println!("Tx hash: {}", tx.hash); + println!("From: {}", tx.from); + println!("To: {}", tx.to.clone().unwrap_or_else(|| "N/A".into())); + println!("Value: {}", tx.value); + println!("Gas: {}", tx.gas); + println!("Gas price: {}", tx.gas_price); + } + + println!("----------------------"); + println!("Ispisano je {} transakcija", transactions.len()); +} + +pub fn find_max_gas_transaction(transactions: &[SimpleTransaction]) -> Option<&SimpleTransaction> { + transactions + .iter() + .max_by_key(|tx| u64::from_str_radix(tx.gas.trim_start_matches("0x"), 16).unwrap_or(0)) +} From 512a6a440e5e12dbce9dae35807515ff9aed96b9 Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Tue, 7 Oct 2025 12:51:16 +0200 Subject: [PATCH 5/9] feat: add consume_and_calculate_gas (ownership example) - Added consume_and_calculate_gas() to demonstrate ownership semantics - Kept borrowed variant for comparison - Simplified main() by removing Result return type and ? operator --- rustCode/src/main.rs | 36 ++++++++++++++++++--------------- rustCode/src/utils/functions.rs | 24 ++++++++++++++++++++++ rustCode/src/utils/mod.rs | 33 ++++-------------------------- rustCode/src/utils/prints.rs | 24 ++++++++++++++++++++++ 4 files changed, 72 insertions(+), 45 deletions(-) create mode 100644 rustCode/src/utils/functions.rs create mode 100644 rustCode/src/utils/prints.rs diff --git a/rustCode/src/main.rs b/rustCode/src/main.rs index 49b227f..9f524b9 100644 --- a/rustCode/src/main.rs +++ b/rustCode/src/main.rs @@ -5,24 +5,24 @@ mod utils; use config::{get_testnet_rpc_url, get_mainnet_rpc_url, load_testnet_env}; use rpc::fetch::{fetch_latest_block, fetch_block_by_number, fetch_transaction_receipt}; -use utils::{print_block_info, print_transactions, find_max_gas_transaction}; +use utils::{print_block_info, print_transactions, find_max_gas_transaction, hex_to_u64, calculate_gas_percentage, consume_and_calculate_gas}; use tokio; #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() { load_testnet_env(); let testnet_rpc_url = get_testnet_rpc_url(); - let block = fetch_latest_block(&testnet_rpc_url, true).await; print_block_info(&block); println!("----------------------"); - let mainnet_rpc_url = get_mainnet_rpc_url(); - println!("{}",mainnet_rpc_url); + let mainnet_rpc_url = get_mainnet_rpc_url(); + let block_response = fetch_block_by_number(&mainnet_rpc_url,"latest" , true).await; print_block_info(&block_response); + let transactions = block_response.transactions; print_transactions(&transactions); @@ -32,23 +32,27 @@ async fn main() -> Result<(), Box> { println!("Transakcija sa najvecim gas limitom: "); println!("Hash {}", max_tx.hash); println!("Gas limit: (hex): {}", max_tx.gas); + println!(); let receipt = fetch_transaction_receipt(&mainnet_rpc_url, &max_tx.hash).await; - //println!("{:?}", receipt); - - let tx_gas_used = - u64::from_str_radix(receipt.gas_used.trim_start_matches("0x"), 16).unwrap_or(0); - let block_gas_used = - u64::from_str_radix(block_response.gas_used.trim_start_matches("0x"), 16).unwrap_or(1); - - let percent_of_block = (tx_gas_used as f64 / block_gas_used as f64) * 100.0; - + //println!("{:?}", receipt); // OVO MOZE + let tx_gas_used = hex_to_u64(&receipt.gas_used); + let block_gas_used = hex_to_u64(&block_response.gas_used); + let percent_of_block = calculate_gas_percentage(tx_gas_used, block_gas_used); + println!("Gas potrosen od ove transakcije: {}", tx_gas_used); println!("Gas potrosen u bloku: {}", block_gas_used); println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block); + println!(); + + println!("Funkcija uzima ownership"); + let percent_of_block1 = consume_and_calculate_gas(receipt, block_response.gas_used); + println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block1); + //println!("{:?}", receipt); //OVO NE MOZE jer je promenjen owner + //println!("{}",block_response.gas_used); + //let tx_gas_used1 = hex_to_u64(&receipt.gas_used); + //let block_gas_used1 = hex_to_u64(&block_response.gas_used); } else { println!("Nema transakcija u ovom bloku"); } - - Ok(()) } diff --git a/rustCode/src/utils/functions.rs b/rustCode/src/utils/functions.rs new file mode 100644 index 0000000..9050dbc --- /dev/null +++ b/rustCode/src/utils/functions.rs @@ -0,0 +1,24 @@ +use crate::models::{SimpleTransaction, TransactionReceipt}; + +pub fn find_max_gas_transaction(transactions: &[SimpleTransaction]) -> Option<&SimpleTransaction> { + transactions + .iter() + .max_by_key(|tx| u64::from_str_radix(tx.gas.trim_start_matches("0x"), 16).unwrap_or(0)) +} + +pub fn hex_to_u64(hex: &str) -> u64 { + u64::from_str_radix(hex.trim_start_matches("0x"), 16).unwrap_or(0) +} + +pub fn calculate_gas_percentage(tx_gas_used: u64, block_gas_used: u64) -> f64 { + if block_gas_used == 0 { + return 0.0; + } + (tx_gas_used as f64 / block_gas_used as f64) * 100.0 +} + +pub fn consume_and_calculate_gas(receipt: TransactionReceipt, block_gas_used_hex: String) -> f64 { + let tx_gas_used = hex_to_u64(&receipt.gas_used); + let block_gas_used = hex_to_u64(&block_gas_used_hex); + calculate_gas_percentage(tx_gas_used, block_gas_used) +} \ No newline at end of file diff --git a/rustCode/src/utils/mod.rs b/rustCode/src/utils/mod.rs index 83aeeb6..1494b89 100644 --- a/rustCode/src/utils/mod.rs +++ b/rustCode/src/utils/mod.rs @@ -1,30 +1,5 @@ -use crate::models::{SimpleBlock, SimpleTransaction}; +pub mod prints; +pub mod functions; -pub fn print_block_info(block: &SimpleBlock) { - println!("Blok broj: {}", block.number); - println!("Hash bloka: {}", block.hash); - println!("Timestamp: {}", block.timestamp); - println!("Gas used: {}", block.gas_used); - println!("Broj transakcija: {}", block.transactions.len()); -} - -pub fn print_transactions(transactions: &[SimpleTransaction]) { - for tx in transactions { - println!("---"); - println!("Tx hash: {}", tx.hash); - println!("From: {}", tx.from); - println!("To: {}", tx.to.clone().unwrap_or_else(|| "N/A".into())); - println!("Value: {}", tx.value); - println!("Gas: {}", tx.gas); - println!("Gas price: {}", tx.gas_price); - } - - println!("----------------------"); - println!("Ispisano je {} transakcija", transactions.len()); -} - -pub fn find_max_gas_transaction(transactions: &[SimpleTransaction]) -> Option<&SimpleTransaction> { - transactions - .iter() - .max_by_key(|tx| u64::from_str_radix(tx.gas.trim_start_matches("0x"), 16).unwrap_or(0)) -} +pub use prints::*; +pub use functions::*; \ No newline at end of file diff --git a/rustCode/src/utils/prints.rs b/rustCode/src/utils/prints.rs new file mode 100644 index 0000000..ef4998e --- /dev/null +++ b/rustCode/src/utils/prints.rs @@ -0,0 +1,24 @@ +use crate::models::{SimpleBlock, SimpleTransaction}; + +pub fn print_block_info(block: &SimpleBlock) { + println!("Blok broj: {}", block.number); + println!("Hash bloka: {}", block.hash); + println!("Timestamp: {}", block.timestamp); + println!("Gas used: {}", block.gas_used); + println!("Broj transakcija: {}", block.transactions.len()); +} + +pub fn print_transactions(transactions: &[SimpleTransaction]) { + for tx in transactions { + println!("---"); + println!("Tx hash: {}", tx.hash); + println!("From: {}", tx.from); + println!("To: {}", tx.to.clone().unwrap_or_else(|| "N/A".into())); + println!("Value: {}", tx.value); + println!("Gas: {}", tx.gas); + println!("Gas price: {}", tx.gas_price); + } + + println!("----------------------"); + println!("Ispisano je {} transakcija", transactions.len()); +} \ No newline at end of file From 324a003d848540cf4777061c259405c148c4d2f2 Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Tue, 7 Oct 2025 13:17:22 +0200 Subject: [PATCH 6/9] refactor: remove unused RPC structs and allow dead code in TransactionReceipt --- rustCode/src/models/mod.rs | 13 +------------ rustCode/src/rpc/fetch.rs | 4 ++-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/rustCode/src/models/mod.rs b/rustCode/src/models/mod.rs index 45062a8..ccbecec 100644 --- a/rustCode/src/models/mod.rs +++ b/rustCode/src/models/mod.rs @@ -27,23 +27,12 @@ pub struct SimpleTransaction { pub gas_price: String, } -#[derive(Debug, Deserialize)] -pub struct RPCResponseBlockTransactions { - pub result: BlockTransactions, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BlockTransactions { - pub block_hash: String, - pub transactions: Vec, -} - #[derive(Debug, Deserialize)] pub struct RPCResponseReceipt { pub result: TransactionReceipt, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionReceipt { diff --git a/rustCode/src/rpc/fetch.rs b/rustCode/src/rpc/fetch.rs index 35a0d0c..0d036e4 100644 --- a/rustCode/src/rpc/fetch.rs +++ b/rustCode/src/rpc/fetch.rs @@ -1,6 +1,6 @@ -use crate::models::{BlockTransactions, RPCResponseBlock, RPCResponseBlockTransactions, RPCResponseReceipt, SimpleBlock, TransactionReceipt}; +use crate::models::{RPCResponseBlock, RPCResponseReceipt, SimpleBlock, TransactionReceipt}; use reqwest::Client; -use serde_json::{json, Value}; +use serde_json::json; pub async fn fetch_latest_block(rpc_url: &str, transaction_bool: bool) -> SimpleBlock { let req_body = json!( { From 21894c1adc141d7b657fa85229c22440a50ea011 Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Tue, 7 Oct 2025 16:05:49 +0200 Subject: [PATCH 7/9] perf: speed up block fetching by running RPC calls concurrently with tokio::join! --- rustCode/src/lib.rs | 2 +- rustCode/src/main.rs | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/rustCode/src/lib.rs b/rustCode/src/lib.rs index b32e637..b19f11b 100644 --- a/rustCode/src/lib.rs +++ b/rustCode/src/lib.rs @@ -30,6 +30,6 @@ pub extern "C" fn fetch_transactions(rpc_url: *const c_char) -> *mut c_char { let c_str_result = CString::new(transaction_data).unwrap(); - // Vracanje C stringa koji Go moye koristiti + // Vracanje C stringa koji Go moze koristiti c_str_result.into_raw() } diff --git a/rustCode/src/main.rs b/rustCode/src/main.rs index 9f524b9..7620bd6 100644 --- a/rustCode/src/main.rs +++ b/rustCode/src/main.rs @@ -13,17 +13,21 @@ async fn main() { load_testnet_env(); let testnet_rpc_url = get_testnet_rpc_url(); - let block = fetch_latest_block(&testnet_rpc_url, true).await; - print_block_info(&block); + let mainnet_rpc_url = get_mainnet_rpc_url(); + + + let (block_testnet, block_mainnet) = tokio::join!( + fetch_latest_block(&testnet_rpc_url, true), + fetch_block_by_number(&mainnet_rpc_url, "latest", true) + ); + println!("Testnet blok:"); + print_block_info(&block_testnet); println!("----------------------"); + println!("Mainnet blok:"); + print_block_info(&block_mainnet); - let mainnet_rpc_url = get_mainnet_rpc_url(); - - let block_response = fetch_block_by_number(&mainnet_rpc_url,"latest" , true).await; - print_block_info(&block_response); - - let transactions = block_response.transactions; + let transactions = block_mainnet.transactions; print_transactions(&transactions); println!("----------------------"); @@ -37,7 +41,7 @@ async fn main() { let receipt = fetch_transaction_receipt(&mainnet_rpc_url, &max_tx.hash).await; //println!("{:?}", receipt); // OVO MOZE let tx_gas_used = hex_to_u64(&receipt.gas_used); - let block_gas_used = hex_to_u64(&block_response.gas_used); + let block_gas_used = hex_to_u64(&block_mainnet.gas_used); let percent_of_block = calculate_gas_percentage(tx_gas_used, block_gas_used); println!("Gas potrosen od ove transakcije: {}", tx_gas_used); @@ -46,7 +50,7 @@ async fn main() { println!(); println!("Funkcija uzima ownership"); - let percent_of_block1 = consume_and_calculate_gas(receipt, block_response.gas_used); + let percent_of_block1 = consume_and_calculate_gas(receipt, block_mainnet.gas_used); println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block1); //println!("{:?}", receipt); //OVO NE MOZE jer je promenjen owner //println!("{}",block_response.gas_used); From afac2da14f30d2805a16fb5bd4257f2ad9c1c85d Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Wed, 8 Oct 2025 02:28:21 +0200 Subject: [PATCH 8/9] feat(rpc): add async fetch_last_5_blocks_and_receipts and extract analyze_max_gas_transaction - implemented parallel fetching of last 5 blocks using Tokio - moved transaction analysis logic into a separate function for reusability - improved modularity and readability of async RPC handling --- rustCode/Cargo.toml | 1 + rustCode/src/lib.rs | 1 + rustCode/src/main.rs | 51 +++++++++++++------------------ rustCode/src/models/mod.rs | 10 +++++++ rustCode/src/rpc/fetch.rs | 53 ++++++++++++++++++++++++++++++++- rustCode/src/utils/functions.rs | 39 ++++++++++++++++++++++++ rustCode/src/utils/prints.rs | 1 + 7 files changed, 124 insertions(+), 32 deletions(-) diff --git a/rustCode/Cargo.toml b/rustCode/Cargo.toml index 2f3ac1d..01be590 100644 --- a/rustCode/Cargo.toml +++ b/rustCode/Cargo.toml @@ -14,3 +14,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" reqwest = { version = "0.11", features = ["json"] } dotenvy = "0.15" +futures = "0.3.31" diff --git a/rustCode/src/lib.rs b/rustCode/src/lib.rs index b19f11b..41ecaa9 100644 --- a/rustCode/src/lib.rs +++ b/rustCode/src/lib.rs @@ -1,5 +1,6 @@ pub mod models; pub mod rpc; +pub mod utils; use crate::rpc::fetch::fetch_latest_block; use std::ffi::CString; diff --git a/rustCode/src/main.rs b/rustCode/src/main.rs index 7620bd6..2fe3ccb 100644 --- a/rustCode/src/main.rs +++ b/rustCode/src/main.rs @@ -4,8 +4,8 @@ mod rpc; mod utils; use config::{get_testnet_rpc_url, get_mainnet_rpc_url, load_testnet_env}; -use rpc::fetch::{fetch_latest_block, fetch_block_by_number, fetch_transaction_receipt}; -use utils::{print_block_info, print_transactions, find_max_gas_transaction, hex_to_u64, calculate_gas_percentage, consume_and_calculate_gas}; +use rpc::fetch::{fetch_latest_block, fetch_block_by_number, fetch_last_5_blocks_and_receipts}; +use utils::{print_block_info, hex_to_u64, analyze_max_gas_transaction}; use tokio; #[tokio::main] @@ -28,35 +28,24 @@ async fn main() { print_block_info(&block_mainnet); let transactions = block_mainnet.transactions; - print_transactions(&transactions); + //print_transactions(&transactions); - println!("----------------------"); - - if let Some(max_tx) = find_max_gas_transaction(&transactions){ - println!("Transakcija sa najvecim gas limitom: "); - println!("Hash {}", max_tx.hash); - println!("Gas limit: (hex): {}", max_tx.gas); - println!(); - - let receipt = fetch_transaction_receipt(&mainnet_rpc_url, &max_tx.hash).await; - //println!("{:?}", receipt); // OVO MOZE - let tx_gas_used = hex_to_u64(&receipt.gas_used); - let block_gas_used = hex_to_u64(&block_mainnet.gas_used); - let percent_of_block = calculate_gas_percentage(tx_gas_used, block_gas_used); + analyze_max_gas_transaction(&mainnet_rpc_url, &transactions, &block_mainnet.gas_used).await; - println!("Gas potrosen od ove transakcije: {}", tx_gas_used); - println!("Gas potrosen u bloku: {}", block_gas_used); - println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block); - println!(); - - println!("Funkcija uzima ownership"); - let percent_of_block1 = consume_and_calculate_gas(receipt, block_mainnet.gas_used); - println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block1); - //println!("{:?}", receipt); //OVO NE MOZE jer je promenjen owner - //println!("{}",block_response.gas_used); - //let tx_gas_used1 = hex_to_u64(&receipt.gas_used); - //let block_gas_used1 = hex_to_u64(&block_response.gas_used); - } else { - println!("Nema transakcija u ovom bloku"); + println!(); + println!("======================="); + println!("Fetchujem 5 poslednjih blokova i njihove max gas transakcije..."); + println!("=======================\n"); + + let latest_block_number = hex_to_u64(&block_mainnet.number); + let summaries = fetch_last_5_blocks_and_receipts(mainnet_rpc_url, latest_block_number).await; + + println!("\n===== REZIME 5 BLOKOVA ====="); + for s in summaries { + println!( + "Blok {} | TX {} | Gas {} | {:.3}%", + s.block_number, s.tx_hash, s.gas_used, s.percent_in_block + ); } -} + +} \ No newline at end of file diff --git a/rustCode/src/models/mod.rs b/rustCode/src/models/mod.rs index ccbecec..45dbbb1 100644 --- a/rustCode/src/models/mod.rs +++ b/rustCode/src/models/mod.rs @@ -15,6 +15,7 @@ pub struct SimpleBlock { pub transactions: Vec, } +#[allow(dead_code)] #[derive(Debug, Deserialize)] pub struct SimpleTransaction { pub hash: String, @@ -36,7 +37,16 @@ pub struct RPCResponseReceipt { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionReceipt { + pub block_hash: String, + pub block_number: String, pub transaction_hash: String, pub gas_used: String, pub cumulative_gas_used: String, +} + +pub struct TxSummary { + pub block_number: String, + pub tx_hash: String, + pub gas_used: u64, + pub percent_in_block: f64, } \ No newline at end of file diff --git a/rustCode/src/rpc/fetch.rs b/rustCode/src/rpc/fetch.rs index 0d036e4..69b5f16 100644 --- a/rustCode/src/rpc/fetch.rs +++ b/rustCode/src/rpc/fetch.rs @@ -1,6 +1,8 @@ -use crate::models::{RPCResponseBlock, RPCResponseReceipt, SimpleBlock, TransactionReceipt}; +use crate::models::{RPCResponseBlock, RPCResponseReceipt, SimpleBlock, TransactionReceipt, TxSummary}; use reqwest::Client; use serde_json::json; +use std::sync::Arc; +use crate::utils::{find_max_gas_transaction, hex_to_u64, calculate_gas_percentage}; pub async fn fetch_latest_block(rpc_url: &str, transaction_bool: bool) -> SimpleBlock { let req_body = json!( { @@ -65,4 +67,53 @@ pub async fn fetch_transaction_receipt(rpc_url: &str, tx_hash: &str) -> Transact let receipt_resp: RPCResponseReceipt = resp.json().await.expect("Greska pri parsiranju odgovora"); receipt_resp.result +} + +pub async fn fetch_last_5_blocks_and_receipts(rpc_url: String, latest_block_number: u64) +-> Vec { + let rpc_arc = Arc::new(rpc_url); + + let mut tasks = Vec::new(); + + for i in 0..5 { + let rpc = Arc::clone(&rpc_arc); + let block_number = latest_block_number.saturating_sub(i); // da ne padne ispod 0 + + let task = tokio::spawn(async move { + let block_number_hex = format!("0x{:x}", block_number); + let block = fetch_block_by_number(&rpc, &block_number_hex, true).await; + + if let Some(max_tx) = find_max_gas_transaction(&block.transactions) { + let receipt = fetch_transaction_receipt(&rpc, &max_tx.hash).await; + let tx_gas_used = hex_to_u64(&receipt.gas_used); + let block_gas_used = hex_to_u64(&block.gas_used); + let percent = calculate_gas_percentage(tx_gas_used, block_gas_used); + + println!( + "Blok {} | Max TX: {} | Gas: {} | %. u bloku: {:.3}%", + block.number, max_tx.hash, tx_gas_used, percent + ); + + Some(TxSummary { + block_number: block.number.clone(), + tx_hash: max_tx.hash.clone(), + gas_used: tx_gas_used, + percent_in_block: percent, + }) + } else { + println!("Blok {} nema transakcije.", block.number); + None + } + }); + + tasks.push(task); + } + + let results = futures::future::join_all(tasks).await; + + // filtriram samo uspesne + results + .into_iter() + .filter_map(|res| res.ok().flatten()) + .collect() } \ No newline at end of file diff --git a/rustCode/src/utils/functions.rs b/rustCode/src/utils/functions.rs index 9050dbc..f1e7b3c 100644 --- a/rustCode/src/utils/functions.rs +++ b/rustCode/src/utils/functions.rs @@ -1,4 +1,5 @@ use crate::models::{SimpleTransaction, TransactionReceipt}; +use crate::rpc::fetch::fetch_transaction_receipt; pub fn find_max_gas_transaction(transactions: &[SimpleTransaction]) -> Option<&SimpleTransaction> { transactions @@ -21,4 +22,42 @@ pub fn consume_and_calculate_gas(receipt: TransactionReceipt, block_gas_used_hex let tx_gas_used = hex_to_u64(&receipt.gas_used); let block_gas_used = hex_to_u64(&block_gas_used_hex); calculate_gas_percentage(tx_gas_used, block_gas_used) +} + +pub async fn analyze_max_gas_transaction( + mainnet_rpc_url: &str, + transactions: &[SimpleTransaction], + block_gas_used_hex: &str, +) { + println!("----------------------"); + + if let Some(max_tx) = find_max_gas_transaction(transactions) { + println!("Transakcija sa najvecim gas limitom: "); + println!("Hash {}", max_tx.hash); + println!("Gas limit: {}", hex_to_u64(&max_tx.gas)); + println!(); + + let receipt = fetch_transaction_receipt(mainnet_rpc_url, &max_tx.hash).await; + //println!("{:?}", receipt); // OVO MOZE + let tx_gas_used = hex_to_u64(&receipt.gas_used); + let block_gas_used = hex_to_u64(block_gas_used_hex); + let percent_of_block = calculate_gas_percentage(tx_gas_used, block_gas_used); + + println!("Gas potrosen od ove transakcije: {}", tx_gas_used); + println!("Gas potrosen u bloku: {}", block_gas_used); + println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block); + println!(); + + // Ownership primer + println!("Ponovljeno izracunavanje preko dodele ownership-a"); + let percent_of_block1 = consume_and_calculate_gas(receipt, block_gas_used_hex.to_string()); + println!("Procenat potrosnje u bloku: {:.6}%", percent_of_block1); + //println!("{:?}", receipt); //OVO NE MOZE jer je promenjen owner + //println!("{}",block_mainnet.gas_used); + //let tx_gas_used1 = hex_to_u64(&receipt.gas_used); + //let block_gas_used1 = hex_to_u64(&block_mainnet.gas_used); + + } else { + println!("Nema transakcija u ovom bloku"); + } } \ No newline at end of file diff --git a/rustCode/src/utils/prints.rs b/rustCode/src/utils/prints.rs index ef4998e..d7ccdb5 100644 --- a/rustCode/src/utils/prints.rs +++ b/rustCode/src/utils/prints.rs @@ -8,6 +8,7 @@ pub fn print_block_info(block: &SimpleBlock) { println!("Broj transakcija: {}", block.transactions.len()); } +#[allow(dead_code)] pub fn print_transactions(transactions: &[SimpleTransaction]) { for tx in transactions { println!("---"); From e8f63cca2176b0080d919422f4dd43a73ae31613 Mon Sep 17 00:00:00 2001 From: Vukasin Markovic Date: Wed, 8 Oct 2025 03:20:58 +0200 Subject: [PATCH 9/9] feat: add Rust FFI integration for last 5 blocks fetching --- goCode/goApp/main.go | 41 +++++++++++++++++++++++++------- goCode/internal/config/config.go | 9 +++++-- goCode/internal/rpc/types.go | 7 ++++++ rustCode/src/lib.rs | 19 ++++++++++++++- rustCode/src/models/mod.rs | 1 + 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/goCode/goApp/main.go b/goCode/goApp/main.go index 33401a1..5fee1b7 100644 --- a/goCode/goApp/main.go +++ b/goCode/goApp/main.go @@ -6,10 +6,14 @@ package main // fetch_transactions je Rust funkcija koja vraca podatke o transakcijama iz poslednjeg bloka char* fetch_transactions(const char* rpc_url); + +// fetch_last_5_blocks je Rust funkcija koja vraca podatke o transakciji maksimalnog potrosenog gasa u poslednjih 5 blokova +char* fetch_last_5_blocks(const char* rpc_url); */ import "C" import ( + "encoding/json" "fmt" "unsafe" @@ -21,28 +25,49 @@ import ( func main() { - rpcURL, recipientAddress, privateKeyHex := config.LoadEnv() + rpcTestnetURL, rpcMainnetURL, recipientAddress, privateKeyHex := config.LoadEnv() - blockNumber := rpc.GetLatestBlock(rpcURL) + blockNumber := rpc.GetLatestBlock(rpcTestnetURL) fmt.Println(blockNumber) fmt.Println() fakeBalance := utilis.EthToHex(100) // 100 ETH - transaction.SetFakeBalance(rpcURL, recipientAddress, fakeBalance) + transaction.SetFakeBalance(rpcTestnetURL, recipientAddress, fakeBalance) sendEth := 1 - transaction.SendTransaction(rpcURL, recipientAddress, int64(sendEth), privateKeyHex) + transaction.SendTransaction(rpcTestnetURL, recipientAddress, int64(sendEth), privateKeyHex) - //--------------------------- + // === Deo koji zove Rust FFI za transakcije === fmt.Println() - cRpcURL := C.CString(rpcURL) - defer C.free(unsafe.Pointer(cRpcURL)) + cRpcTestnetURL := C.CString(rpcTestnetURL) + defer C.free(unsafe.Pointer(cRpcTestnetURL)) - result := C.fetch_transactions(cRpcURL) + result := C.fetch_transactions(cRpcTestnetURL) defer C.free(unsafe.Pointer(result)) goResult := C.GoString(result) fmt.Println("Rust FFI: Podaci o transakcijama iz poslednjeg bloka:\n", goResult) + // === Deo koji zove Rust FFI za 5 blokova === + fmt.Println() + + cRpcMainnetURL := C.CString(rpcMainnetURL) + defer C.free(unsafe.Pointer(cRpcMainnetURL)) + + resultArray := C.fetch_last_5_blocks(cRpcMainnetURL) + defer C.free(unsafe.Pointer(resultArray)) + goArray := C.GoString(resultArray) + + var summaries []rpc.TxSummary + err := json.Unmarshal([]byte(goArray), &summaries) + if err != nil { + fmt.Println("Greska pri parsiranju JSON-a iz Rust-a:", err) + return + } + + for _, s := range summaries { + fmt.Printf("Blok %s | TX %s | Gas %d | %.3f%% u bloku\n", + s.BlockNumber, s.TxHash, s.GasUsed, s.PercentInBlock) + } } diff --git a/goCode/internal/config/config.go b/goCode/internal/config/config.go index 4ca9c03..898f749 100644 --- a/goCode/internal/config/config.go +++ b/goCode/internal/config/config.go @@ -7,7 +7,7 @@ import ( "github.com/joho/godotenv" ) -func LoadEnv() (string, string, string) { +func LoadEnv() (string, string, string, string) { err := godotenv.Load("../.env") if err != nil { log.Fatal("Greska pri ucitavanju .env fajla") @@ -18,6 +18,11 @@ func LoadEnv() (string, string, string) { log.Fatal("Nedostaje RPC_TESTNET_URL u .env fajlu") } + rpcMainnetURL := os.Getenv("RPC_MAINNET_URL") + if rpcTestnetURL == "" { + log.Fatal("Nedostaje RPC_TESTNET_URL u .env fajlu") + } + recipient := os.Getenv("RECIPIENT_ADDRESS") if recipient == "" { log.Fatal("Nedostaje RECIPIENT_ADDRESS u .env fajlu") @@ -28,5 +33,5 @@ func LoadEnv() (string, string, string) { log.Fatal("Nedostaje PRIVATE_KEY u .env fajlu") } - return rpcTestnetURL, recipient, privateKeyHex + return rpcTestnetURL, rpcMainnetURL, recipient, privateKeyHex } diff --git a/goCode/internal/rpc/types.go b/goCode/internal/rpc/types.go index 42ca5f8..5493eb4 100644 --- a/goCode/internal/rpc/types.go +++ b/goCode/internal/rpc/types.go @@ -30,3 +30,10 @@ type Transaction struct { Gas string `json:"gas"` GasPrice string `json:"gasPrice"` } + +type TxSummary struct { + BlockNumber uint64 `json:"block_number"` + TxHash string `json:"tx_hash"` + GasUsed uint64 `json:"gas_used"` + PercentInBlock float64 `json:"percent_in_block"` +} diff --git a/rustCode/src/lib.rs b/rustCode/src/lib.rs index 41ecaa9..9ec0f3a 100644 --- a/rustCode/src/lib.rs +++ b/rustCode/src/lib.rs @@ -2,9 +2,10 @@ pub mod models; pub mod rpc; pub mod utils; -use crate::rpc::fetch::fetch_latest_block; +use crate::rpc::fetch::{fetch_latest_block, fetch_last_5_blocks_and_receipts}; use std::ffi::CString; use std::os::raw::c_char; +use crate::utils::hex_to_u64; #[no_mangle] pub extern "C" fn fetch_transactions(rpc_url: *const c_char) -> *mut c_char { @@ -34,3 +35,19 @@ pub extern "C" fn fetch_transactions(rpc_url: *const c_char) -> *mut c_char { // Vracanje C stringa koji Go moze koristiti c_str_result.into_raw() } + +#[no_mangle] +pub extern "C" fn fetch_last_5_blocks(rpc_url: *const c_char) -> *mut c_char { + let c_rpc = unsafe { std::ffi::CStr::from_ptr(rpc_url) }; + let rpc_url_str = c_rpc.to_str().unwrap(); + + let runtime = tokio::runtime::Runtime::new().unwrap(); + let latest_block = runtime.block_on(fetch_latest_block(rpc_url_str, true)); + let latest_block_number = hex_to_u64(&latest_block.number); + + let summaries = runtime.block_on(fetch_last_5_blocks_and_receipts(rpc_url_str.to_string(), latest_block_number)); + + let json_str = serde_json::to_string(&summaries).unwrap(); + let c_str_result = CString::new(json_str).unwrap(); + c_str_result.into_raw() +} \ No newline at end of file diff --git a/rustCode/src/models/mod.rs b/rustCode/src/models/mod.rs index 45dbbb1..5294d2a 100644 --- a/rustCode/src/models/mod.rs +++ b/rustCode/src/models/mod.rs @@ -44,6 +44,7 @@ pub struct TransactionReceipt { pub cumulative_gas_used: String, } +#[derive(serde::Serialize)] pub struct TxSummary { pub block_number: String, pub tx_hash: String,